贝塞尔二阶曲线

本文介绍了贝塞尔二阶曲线的概念,并详细说明了如何通过控制点来确定曲线上的点。同时,针对Android平台,提供了利用Path进行二阶贝塞尔曲线绘制的方法和示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.贝塞尔二阶曲线

  如下图,由起始点A,控制点C,终点B;
  在AC上找到一点D,BC上找到一点E,使AD/DC=CE/EB;
  连接DE找到一点F使AD/DC=CE/EB=DF/FE;
  F即为贝塞尔曲线上一点。
在这里插入图片描述

2.Android绘制贝塞尔二阶曲线

  Path里面有两个方法可以进行贝塞尔二阶曲线:

	//默认起始点 (0,0),控制点(x1,y1),终点(x2,y2)
	public void quadTo(float x1, float y1, float x2, float y2) {
        isSimplePath = false;
        nQuadTo(mNativePath, x1, y1, x2, y2);
    }

	//相对于上一个控制点(oldX,oldY)的偏移(oldX+dx1,oldY+dy1),相对于上一个终点(x1,y1)的偏移(x1+dx1,y2+dy2)
   public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
        isSimplePath = false;
        nRQuadTo(mNativePath, dx1, dy1, dx2, dy2);
    }
   

  根据这个即可绘制曲线图:

代码如下

public class WaveView extends View {
	private Path			mPath;
	private Path			mLinePath;
	private Paint			mPaintBezier;
	private Paint			mPaintLine;
	private int				mWaveLength;
	private int				mScreenWidth;
	private int				mWaveCount;

	private ValueAnimator	mValueAnimator	= null;

	private int				mOffsetX;
	private int				mOffsetY;

	public WaveView(Context context) {
		super(context);
	}

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

		mPaintBezier = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPaintBezier.setColor(Color.WHITE);
		mPaintBezier.setStrokeWidth(8);
		mPaintBezier.setStyle(Paint.Style.FILL_AND_STROKE);

		mPaintLine = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPaintLine.setStyle(Paint.Style.STROKE);
		mPaintLine.setColor(Color.parseColor("#E3EFF0"));

		int width = DensityUtil.dpTopx(getContext(), 6);
		int interval = DensityUtil.dpTopx(getContext(), 3);
		PathEffect effects = new DashPathEffect(new float[]{width, interval, width, interval}, 1);
		mPaintLine.setPathEffect(effects);
		WindowManager manager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
		Display display = manager.getDefaultDisplay();
		int height = display.getHeight();
        mPaintLine.setStrokeWidth(height);
		mLinePath = new Path();
		mOffsetY = DensityUtil.dpTopx(getContext(), 20);
	}

	public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		mPath = new Path();
		mScreenWidth = w;
		mWaveLength = w * 3 / 5;
		// 此处多加1,是为了预先加载屏幕外的一个波浪,持续报廊移动时的连续性
		mWaveCount = (int) Math.round(mScreenWidth / mWaveLength + 1.5);
	}
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// 绘制底部线条
		mLinePath.reset();
		mLinePath.moveTo(0, 0);
		mLinePath.lineTo(mScreenWidth, 0);
		canvas.drawPath(mLinePath, mPaintLine);
		mPath.reset();
		mPath.moveTo(-mWaveLength + mOffsetX, getHeight() * 2 / 3);
		for (int i = 0; i < mWaveCount; i++) {
			// rQuadTo 相对前一位置偏移量
			// 上凸波浪
			mPath.rQuadTo(mWaveLength / 4, -mOffsetY, mWaveLength / 2, 0);
			// 下凹波浪
			mPath.rQuadTo(mWaveLength / 4, +mOffsetY, mWaveLength / 2, 0);
		}
		mPath.lineTo(mScreenWidth, 0);
		mPath.lineTo(0, 0);
		mPath.close();
		canvas.drawPath(mPath, mPaintBezier);

	}

	public void startAnimation() {
		if (mValueAnimator == null) {
			// 设置动画运动距离
			mValueAnimator = ValueAnimator.ofInt(0, mWaveLength);
			mValueAnimator.setDuration(1000);
			// 循环
			mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
			mValueAnimator.setInterpolator(new LinearInterpolator());
			mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
				@Override
				public void onAnimationUpdate(ValueAnimator valueAnimator) {
					// 获取偏移量,绘制波浪曲线的X横坐标加上此偏移量,产生移动效果
					mOffsetX = (int) valueAnimator.getAnimatedValue();

					invalidate();
				}
			});
		}
		mValueAnimator.start();
	}
	public void stopAnimation() {
		if (mValueAnimator != null) {
			mValueAnimator.pause();
		}
	}

	public boolean getAnimationing(){
		if(mValueAnimator!=null){
			return !mValueAnimator.isPaused();
		}
		return false;
	}
}

其他

贝塞尔三阶曲线:调用方法和二阶曲线类似

/**
     * Add a cubic bezier from the last point, approaching control points
     * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
     * made for this contour, the first point is automatically set to (0,0).
     *
     * @param x1 The x-coordinate of the 1st control point on a cubic curve
     * @param y1 The y-coordinate of the 1st control point on a cubic curve
     * @param x2 The x-coordinate of the 2nd control point on a cubic curve
     * @param y2 The y-coordinate of the 2nd control point on a cubic curve
     * @param x3 The x-coordinate of the end point on a cubic curve
     * @param y3 The y-coordinate of the end point on a cubic curve
     */
    public void cubicTo(float x1, float y1, float x2, float y2,
                        float x3, float y3) {
        isSimplePath = false;
        nCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
    }

    /**
     * Same as cubicTo, but the coordinates are considered relative to the
     * current point on this contour. If there is no previous point, then a
     * moveTo(0,0) is inserted automatically.
     */
    public void rCubicTo(float x1, float y1, float x2, float y2,
                         float x3, float y3) {
        isSimplePath = false;
        nRCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值