android使用贝塞尔曲线做一个简单的玩意

效果挺简单的 ,简单说下思路。





这个图由7个点确定:两个圆心P1,P2,每个圆的两个对称点P3,P4,P5,P6,以及两个圆心的终点P7(P5,P6,P7图中没画,相信大家清楚)

点的获取:首先选取一个固定点作为中间不动的球的圆心,然后在onTouchEvent中记录按下的点重新绘制,难点在于每个球取的点的获取,动球在固定的球的左上,右上,左下,右下方向时,sin α和cos α值会有正负变化,如图以动圆在固定圆的右下方为例:

点P4的坐标为:

P4.x = P1.x - r * sin α

P4.y = P1.y + r * cos α

点P3的坐标为:

P3.x = P2.x - r * sin α

P3.y = P2.y + r * cos α

以P3为例,P3相对圆心P2的对称点P5(图中没画)的坐标为:

P5.x = 2 * P2.x - P3.x

P5.y = 2 * P2.y - P3.y

P4的对称点类似写法。

好了,点找完了 接下来画图吧,直接上代码:

 
 
 
 
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by Administrator on 2017/5/16.
 */

public class BezierView extends View  {
    private static final String TAG = "wsy";
    private Paint mPaint,mCirclePaint;
    private Path mPath1,mPath2;
    private Point startPoint;
    private Point endPoint;
    private Point centerPoint;
    private Point startPointEdge1,startPointEdge2;  //起点两个边界点
    private Point endPointEdge1,endPointEdge2;    //终点两个边界点
    private int radius=50;  //初始半径
    public BezierView(Context context) {
        super(context);
        init(context);
    }

    public BezierView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public BezierView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        getPointsByCenterAndRadius();

        mPath1.reset();
        mPath1.moveTo(startPointEdge1.x, startPointEdge1.y);
        mPath1.quadTo(centerPoint.x, centerPoint.y, endPointEdge1.x, endPointEdge1.y);

        mPath2.reset();
        mPath2.moveTo(startPointEdge2.x, startPointEdge2.y);
        mPath2.quadTo(centerPoint.x, centerPoint.y, endPointEdge2.x, endPointEdge2.y);

        // 画路径
        canvas.drawPath(mPath2, mPaint);
        canvas.drawPath(mPath1, mPaint);
        canvas.drawCircle(startPoint.x,startPoint.y,radius,mCirclePaint);
        canvas.drawCircle(endPoint.x,endPoint.y,radius,mCirclePaint);
//        canvas.drawOval(startPoint.x - radius,startPoint.y - radius, startPoint.x + radius , startPoint.y + radius,mPaint);
//        canvas.drawOval(endPoint.x - radius,endPoint.y - radius, endPoint.x + radius , endPoint.y + radius,mPaint);
    }

    private void init(Context context) {
        mPaint = new Paint();
        mCirclePaint = new Paint();
        mPath1 = new Path();
        mPath2 = new Path();
        startPoint = new Point(600, 600);
        centerPoint = new Point(350,350);
        endPoint = new Point(100, 100);
        startPointEdge1 = new Point();
        startPointEdge2 = new Point();
        endPointEdge1 = new Point();
        endPointEdge2 = new Point();

        mPaint.setStrokeWidth(2);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.RED);

        mCirclePaint.setColor(Color.RED);
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setStrokeWidth(100);
        mCirclePaint.setDither(true);
    }

    private void getPointsByCenterAndRadius()
    {
        centerPoint.x = (startPoint.x+endPoint.x)/2;
        centerPoint.y = (startPoint.y+endPoint.y)/2;
        double startToEndK ; //起点和终点的连线斜率
        double sin ,cos;
        startToEndK = (double) (startPoint.y - endPoint.y) / (double)(startPoint.x - endPoint.x);
        cos =  Math.pow(1/(startToEndK*startToEndK+1),0.5);
        sin =  Math.pow(startToEndK*startToEndK/(startToEndK*startToEndK+1),0.5);

        radius = (int) (50 + Math.pow(((endPoint.y - startPoint.y)*(endPoint.y - startPoint.y) + (endPoint.x - startPoint.x)*(endPoint.x - startPoint.x)),0.5)/15);
        if ((endPoint.x>startPoint.x&&endPoint.y>startPoint.y)||(endPoint.x<startPoint.x&&endPoint.y<startPoint.y))  //右下角或左上角
        {
            startPointEdge1.x = (int) (startPoint.x - radius*sin);   //根据tan获得cos 和sin 再获得第一个边界点的x和y
            startPointEdge1.y = (int) (startPoint.y + radius*cos);

            startPointEdge2.x = startPoint.x * 2 - startPointEdge1.x;
            startPointEdge2.y = startPoint.y * 2 - startPointEdge1.y;


            endPointEdge1.x = (int) (endPoint.x - radius*sin);   //根据tan获得cos 和sin 再获得第一个边界点的x和y
            endPointEdge1.y = (int) (endPoint.y + radius*cos);

            endPointEdge2.x = endPoint.x * 2 - endPointEdge1.x;
            endPointEdge2.y = endPoint.y * 2 - endPointEdge1.y;

        }else if ((endPoint.x>startPoint.x&&endPoint.y<startPoint.y) ||(endPoint.x<startPoint.x&&endPoint.y>startPoint.y) ) //右上角或者左下角
        {
            startPointEdge1.x = (int) (startPoint.x + radius*sin);   //根据tan获得cos 和sin 再获得第一个边界点的x和y
            startPointEdge1.y = (int) (startPoint.y + radius*cos);

            startPointEdge2.x = startPoint.x * 2 - startPointEdge1.x;
            startPointEdge2.y = startPoint.y * 2 - startPointEdge1.y;


            endPointEdge1.x = (int) (endPoint.x + radius*sin);
            endPointEdge1.y = (int) (endPoint.y + radius*cos);

            endPointEdge2.x = endPoint.x * 2 - endPointEdge1.x;
            endPointEdge2.y = endPoint.y * 2 - endPointEdge1.y;
        }
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                endPoint.x = (int) event.getX();
                endPoint.y = (int) event.getY();

                invalidate();
                break;
        }
        return true;
    }
}


 
 
 
 
 
 
 
 
 
 
 

猜你喜欢

转载自blog.csdn.net/qq_18757521/article/details/72639259