检查Android中的路径是否与自身相交

时间:2018-02-09 17:29:45

标签: java android canvas path

我有一个问题。

如何检查Android中的路径是否与自身相交?

我有这堂课:

public class GameView extends SurfaceView implements Runnable {

    Thread gameThread = null;

    SurfaceHolder surfaceHolder;

    volatile boolean playing;

    Canvas canvas;

    private final static int MAX_FPS = 60;
    private final static int FRAME_PERIOD =  1000 / MAX_FPS;

    ArrayList<Point> points = new ArrayList<>();

    private Context ctx;

    Path path;

    public static final int DEFAULT_COLOR = Color.RED;
    public static final int DEFAULT_BG_COLOR = Color.WHITE;

    private static final float TOUCH_TOLERANCE = 4;

    private float mX, mY;
    private Path mPath;
    private Paint mPaint;
    private int backgroundColor = DEFAULT_BG_COLOR;


    public GameView(Context context) {
        super(context);

        ctx = context;

        surfaceHolder = getHolder();
        surfaceHolder.setFormat(PixelFormat.RGBA_8888);

        path = new Path();


        playing = true;
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(DEFAULT_COLOR);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setXfermode(null);
        mPaint.setAlpha(0xff);
        mPaint.setStrokeWidth(12);

    }


    static Boolean isPathComplex(List<Point> path) {

        if (path == null || path.size() <= 2) {
            return false;
        }

        int len = path.size();

        for (int i = 1; i < len; i++) {
            Point lineAStart = path.get(i - 1);
            Point lineAEnd = path.get(i);

            for (int j = i + 1; j < len; j++) {
                Point lineBStart = path.get(j - 1);
                Point lineBEnd = path.get(j);
                if (lineSegmentsIntersect(lineAStart.x,lineAStart.y,
                        lineAEnd.x,lineAEnd.y,
                        lineBStart.x,lineBStart.y,
                        lineBEnd.x,lineBEnd.y)) {
                    return true;
                }

            } // inner loop

        } // outer loop

        return false;
    }


    static Boolean lineSegmentsIntersect(float p0_x, float p0_y, float p1_x, float p1_y,
                                         float p2_x, float p2_y, float p3_x, float p3_y) {
        float s1_x, s1_y, s2_x, s2_y;
        s1_x = p1_x - p0_x;     s1_y = p1_y - p0_y;
        s2_x = p3_x - p2_x;     s2_y = p3_y - p2_y;

        float s, t;
        s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
        t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

        if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
        {
            // Collision detected

            return true;
        }

        return false; // No collision
    }



    public void update(){
        isPathComplex(points);
    }


    public void draw(){
        if(surfaceHolder.getSurface().isValid()){
            canvas = surfaceHolder.lockCanvas();

            if(canvas != null) {
                canvas.drawColor(backgroundColor);

                if (mPath != null) {

                    canvas.drawPath(mPath, mPaint);
                }

                surfaceHolder.unlockCanvasAndPost(canvas);
            }
        }
    }


    @Override
    public void run() {

        while(playing){

            long started = System.currentTimeMillis();

            float deltaTime = (System.currentTimeMillis() - started);

            int sleepTime = (int) (FRAME_PERIOD - deltaTime);

            update();
            draw();

            if (sleepTime > 0) {
                try {
                    Thread.sleep(sleepTime);
                }
                catch (InterruptedException e) {
                }
            }
            while (sleepTime < 0) {
                update();
                draw();
                sleepTime += FRAME_PERIOD;
            }
        }

    }  


   private void touchStart(float x, float y) {
        mPath = new Path();
        points.add(new Point((int)x,(int)y));
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }


    private void touchMove(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        points.add(new Point((int)x,(int)y));

        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);

            mX = x;
            mY = y;
        }
    }


    private void touchUp() {
        mPath.lineTo(mX, mY);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch(event.getAction()) {
            case MotionEvent.ACTION_DOWN :
                touchStart(x, y);
                break;
            case MotionEvent.ACTION_MOVE :
                touchMove(x, y);
                break;
            case MotionEvent.ACTION_UP :
                touchUp();
                break;
        }

        return true;
    }


    public void pause() {
        playing = false;
        try {
            gameThread.join();
        } catch (InterruptedException e) {
            Log.e("Error:", "joining thread");
        }

    }


    public void resume(Context context) {
        playing = true;
        gameThread = new Thread(this);
        gameThread.start();
    }

}

请您知道解决此问题的方法吗?

我尝试了很多,但没有任何帮助我解决我的问题。

我想要实现的是检测像this

这样的交叉

我尝试使用来自Check android.graphics.path intersection with itself的积分解决方案,但似乎不适合我。

我也可能做错了,因为我是Android开发和编程的新手:)。

提前谢谢!

修改

要检测上面的解决方案后面的交叉i并修改了这个函数https://stackoverflow.com/a/1968345/9339525但是它几乎一直都返回true,即使路径没有穿过它自己。

检测交叉口的所有代码:

static Boolean isPathComplex(List<Point> path) {

    if (path == null || path.size() <= 2) {
        return false;
    }

    int len = path.size();

    for (int i = 1; i < len; i++) {
        Point lineAStart = path.get(i - 1);
        Point lineAEnd = path.get(i);

        for (int j = i + 1; j < len; j++) {
            Point lineBStart = path.get(j - 1);
            Point lineBEnd = path.get(j);
            if (lineSegmentsIntersect(lineAStart.x,lineAStart.y,
                    lineAEnd.x,lineAEnd.y,
                    lineBStart.x,lineBStart.y,
                    lineBEnd.x,lineBEnd.y)) {
                return true;
            }

        } // inner loop

    } // outer loop

    return false;
}


static Boolean lineSegmentsIntersect(float p0_x, float p0_y, float p1_x, float p1_y,
                                     float p2_x, float p2_y, float p3_x, float p3_y) {
    float s1_x, s1_y, s2_x, s2_y;
    s1_x = p1_x - p0_x;     s1_y = p1_y - p0_y;
    s2_x = p3_x - p2_x;     s2_y = p3_y - p2_y;

    float s, t;
    s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
    t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
        // Collision detected

        return true;
    }

    return false; // No collision
}

修改

我修改了我的类GameView并添加了检测交集的方法。

1 个答案:

答案 0 :(得分:0)

我无法忍受那是那么困难,所以我打开电脑并编码了一些东西。

我只尝试了几个值,并且不知道如果段的开始 - 结束点重合会发生什么。

请试试。

static boolean lineSegmentsDoIntersect(
          float Ax, float Ay
        , float Bx, float By
        , float Cx, float Cy
        , float Dx, float Dy) {

    // two line segments: AB and CD
    // segment AB intersects segment CD
    // if  A and B on different sides of line through C and D
    // AND C and D on different sides of line through A and B

    // note the difference between line and  segment!

    if ( ! pointsOnDifferentSidesOfLineThrough(Ax, Ay, Bx, By, Cx, Cy, Dx, Dy) )
        return false;

    if ( ! pointsOnDifferentSidesOfLineThrough(Cx, Cy, Dx, Dy, Ax, Ay, Bx, By) )
        return false;

    return true;
}

static boolean pointsOnDifferentSidesOfLineThrough(
          float Ax, float Ay
        , float Bx, float By
        , float x1, float y1
        , float x2, float y2) {

    // determine equation of line through C and D

    // y = ax + b
    // a = (y2-y1)/(x2-x1)   but.. ( x2-x1) not equal to zero
    // y-y1 = a (x-x1)
    // y = a (x-x1) + y1
    // y = ax -ax1 + y1
    // b = -ax1 + y1

    //but.. (x2-x1) not 0

    if ( x2==x1)
    {
        if ( Ax > x1 && Bx > x1 )
            return false;
        if ( Ax < x1 && Bx < x1 )
            return false;

        return true;
    }

    float a = (y2-y1)/(x2-x1);
    float b = -a * x1 + y1;

    float yA = a * Ax + b;
    float yB = a * Bx + b;

    if ( yA > Ay && yB > By )
        return false;
    if ( yA < Ay && yB < By )
        return false;

    return true;
}