1

I have a Custom View which draws lines an saves them to an ArrayList. What I want to be able to do is check if a specified point is on a line inside the Arraylist and return the line. I have been able to do this when the line is straight by using if (l.startX == l.stopX && l.startY < l.stopY but this doesn't work if the line is on an angle. I would also like to do this with drawText and drawCircle. Is there some simple way of doing this that I have missed?

DrawView.java

class Line {
  float startX, startY, stopX, stopY;
  public Line(float startX, float startY, float stopX, float stopY) {
    this.startX = startX;
    this.startY = startY;
    this.stopX = stopX;
    this.stopY = stopY;
  }
  public Line(float startX, float startY) { // for convenience
    this(startX, startY, startX, startY);
  }
}

public class DrawView extends View {
  Paint paint = new Paint();
  ArrayList<Line> lines = new ArrayList<Line>();

  public DrawView(Context context, AttributeSet attrs) {
    super(context, attrs);

    paint.setAntiAlias(true);
    paint.setStrokeWidth(6f);
    paint.setColor(Color.BLACK);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeJoin(Paint.Join.ROUND);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    for (Line l : lines) {
      canvas.drawLine(l.startX, l.startY, l.stopX, l.stopY, paint);
    }
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {

    if (event.getAction() == MotionEvent.ACTION_DOWN) {
      lines.add(new Line(event.getX(), event.getY()));
      return true;
    }
    else if ((event.getAction() == MotionEvent.ACTION_MOVE ||
        event.getAction() == MotionEvent.ACTION_UP) &&
        lines.size() > 0) {
      Line current = lines.get(lines.size() - 1);
      current.stopX = event.getX();
      current.stopY = event.getY();
      Invalidate();
      return true;
    }
    else {
      return false;
    }
  }
}
Caleb Bramwell
  • 1,332
  • 2
  • 12
  • 24

2 Answers2

2

I don't know if there is a canvas library for this but manually you can:

  1. go through your list of lines
  2. form equations for each line in let's say slope-intercept form y = mx + b
  3. plugin in the event.X() and event.Y() into the above equation as x and y for each line
  4. if the 2 sides are equal then your touch event is on that line
Dalmas
  • 26,409
  • 9
  • 67
  • 80
jaesanx
  • 195
  • 1
  • 13
1

After many hours of trying I managed to come up with a an algorithm to check if a point is on a given line using a mixture of slope-intersect formula and if (x = startX && y > startY && y < stopY) Below is the code, it returns true if point is on line otherwise false, hopefully this can save someone time!

public boolean checkPosition(float x, float y, float sx, float sy, float ex, float ey) {
        float mX = ex - sx;
        float mY = ey - sy;
        float smX = sx - ex;
        float smY = sy - ey;
        float pmX = mX;
        float pmY = mY;
        float psmX = smX;
        float psmY = smY;
        float yY = ey - y;
        float xX = ex - x;
        float sX = sx - x;
        float sY = sy - y;
        float m = mY / mX;
        float b = sy - (m * sx);
        if (mX < 0) {
            pmX = mX * - 1;
        }
        if (mY < 0) {
            pmY = mY * - 1;
        }
        if (smX < 0) {
            psmX = smX * - 1;
        }
        if (smY < 0) {
            psmY = smY * - 1;
        }
        if (yY < 0) {
            yY = yY * - 1;
        }
        if (xX < 0) {
            xX = xX * - 1;
        }
        if (sX < 0) {
            sX = sX * - 1;
        }
        if (sY < 0) {
            sY = sY * - 1;
        }
        if (sy == ey && y == sy) {
            if (sx >= ex) {
                if (x <= sx && x >= ex) return true;
                else return false;
            }
            else if (ex >= sx) {
                if (x <= ex && x >= sx) return true;
                else return false;
            }
            else return false;
        }
        else if (sx == ex && x == sx) {
            if (sy >= ey) {
                if (y <= sy && y >= ey) return true;
                else return false;
            }
            else if (ey >= sy) {
                if (y <= ey && y >= sy) return true;
                else return false;
            }
            else return false;
        }
        else if (xX <= pmX && sX <= psmX && yY <= pmY && sY <= psmY) {
            if (y == (m * x) + b) return true;
            else return false;
        }
        else return false;
    }
Caleb Bramwell
  • 1,332
  • 2
  • 12
  • 24
  • Your solution may cause a runtime error if mX=0. I posted a shorter version on http://stackoverflow.com/questions/20887806/does-a-line-contain-a-point/23388247#23388247 which may solve this. – iOS-Coder May 21 '14 at 08:35