绘制贝塞尔曲线通用方法

//计算三次贝塞尔曲线,后面n(n>=3)计算时,都是将点分成一组一组的三次贝塞尔曲线
//计算控制点思路来源:http://www.antigrain.com/research/bezier_interpolation/index.html#PAGE_BEZIER_INTERPOLATION
SkPoint* CalcThreeBezier(Wm5::Vector2d ptw1,Wm5::Vector2d ptw2,Wm5::Vector2d ptw3)
{
	//算出两条边中点,再算出中点连线的中点
	SkPoint midOfPtw12,midOfPtw23,mid,midOfmid12mid,midOfmid23mid;
	midOfPtw12.fX = (ptw1.X()+ptw2.X())/2;
	midOfPtw12.fY = (ptw1.Y()+ptw2.Y())/2;
	midOfPtw23.fX = (ptw2.X()+ptw3.X())/2;
	midOfPtw23.fY = (ptw2.Y()+ptw3.Y())/2;
	mid.fX = (midOfPtw12.fX+midOfPtw23.fX)/2;
	mid.fY = (midOfPtw12.fY+midOfPtw23.fY)/2;
	midOfmid12mid.fX = (ptw1.X()+mid.fX)/2;
	midOfmid12mid.fY = (ptw1.Y()+mid.fY)/2;
	midOfmid23mid.fX = (ptw3.X()+mid.fX)/2;
	midOfmid23mid.fY = (ptw3.Y()+mid.fY)/2;

	//通过两个线段比例,在对应中点连接线上找出控制向量,然后进行平移
	double length1 = (ptw2-ptw1).Length();
	double length2 = Wm5::Vector2d(mid.fX-ptw1.X(),mid.fY-ptw1.Y()).Length();
	double scale = length1/(length1+length2);

	SkPoint pointInLeftLine,pointInMidLine,pointInRightLine;
	pointInLeftLine.fX = midOfPtw12.fX + (midOfmid12mid.fX-midOfPtw12.fX)*scale;
	pointInLeftLine.fY = midOfPtw12.fY + (midOfmid12mid.fY-midOfPtw12.fY)*scale;
	pointInMidLine.fX = midOfPtw12.fX + (midOfPtw23.fX-midOfPtw12.fX)*scale;
	pointInMidLine.fY = midOfPtw12.fY + (midOfPtw23.fY-midOfPtw12.fY)*scale;
	pointInRightLine.fX = midOfPtw23.fX + (midOfmid23mid.fX - midOfPtw23.fX)*scale;
	pointInRightLine.fY = midOfPtw23.fY + (midOfmid23mid.fY - midOfPtw23.fY)*scale;

	Wm5::Vector2d v_conPoint1 = Wm5::Vector2d(pointInLeftLine.fX-midOfPtw12.fX,pointInLeftLine.fY-midOfPtw12.fY);
	Wm5::Vector2d v_conPoint2 = Wm5::Vector2d(pointInMidLine.fX-midOfPtw12.fX,pointInMidLine.fY-midOfPtw12.fY);
	Wm5::Vector2d v_conPoint3 = Wm5::Vector2d(midOfPtw23.fX-pointInMidLine.fX,midOfPtw23.fY-pointInMidLine.fY);
	Wm5::Vector2d v_conPoint4 = Wm5::Vector2d(pointInRightLine.fX-midOfPtw23.fX,pointInRightLine.fY-midOfPtw23.fY);

	//算出控件点
	SkPoint conPoint1,conPoint2,conPoint3,conPoint4;
	conPoint1.fX = (ptw1-v_conPoint1).X();
	conPoint1.fY = (ptw1-v_conPoint1).Y();
	conPoint2.fX = (ptw2-v_conPoint2).X();
	conPoint2.fY = (ptw2-v_conPoint2).Y();
	conPoint3.fX = (ptw2+v_conPoint3).X();
	conPoint3.fY = (ptw2+v_conPoint3).Y();
	conPoint4.fX = (ptw3-v_conPoint4).X();
	conPoint4.fY = (ptw3-v_conPoint4).Y();

	//保存四个控制点
	midConPoint[0] = conPoint1;
	midConPoint[1] = conPoint2;
	midConPoint[2] = conPoint3;
	midConPoint[3] = conPoint4;

	return midConPoint;
}

//绘制贝塞尔曲线函数
void DrawBezier(vector<Point2d> &vectorOfPoint2D,SkCanvas* canvas,SkPaint& paint)
{
	//由于使用双击停止记录点,双击后最后两个重负,需减掉
	int nPointNum = vectorOfPoint2D.size()-1;
	if (nPointNum < 3)
		return;

	//v_pt存储每点的向量,pt存储点,ptCon存储相应控件点
	Wm5::Vector2d *v_pt = new Wm5::Vector2d[nPointNum];
	SkPoint * ptCon = new SkPoint[2*nPointNum-2];
	SkPoint * pt = new SkPoint[nPointNum];
	for (int i = 0; i < nPointNum; i++ )
	{
		v_pt[i] = Wm5::Vector2d(vectorOfPoint2D[i].dX,vectorOfPoint2D[i].dY);
		pt[i].fX = vectorOfPoint2D[i].dX;
		pt[i].fY = vectorOfPoint2D[i].dY;
	}

	//通过将点分割成多组三次贝塞尔曲线,将各个点的控件点保存起来
	int nConPointNum = 0;
	for (int i = 0; i < nPointNum-2; i++ )
	{
		SkPoint *pPoint = CalcThreeBezier(v_pt[i],v_pt[i+1],v_pt[i+2]);
		if (i == 0)
			ptCon[nConPointNum++] = pPoint[0];
		ptCon[nConPointNum++] = pPoint[1];
		ptCon[nConPointNum++] = pPoint[2];
		if (i == nPointNum-3)
			ptCon[nConPointNum++] = pPoint[3];
	}

	//画贝塞尔曲线
	SkPath path;
	nConPointNum = 0;
	path.moveTo(pt[nConPointNum++]);
	for (int i = 0; i < 2*nPointNum-3; i = i+2)
	{
		path.cubicTo(ptCon[i],ptCon[i+1],pt[nConPointNum++]);
	}
	canvas->drawPath(path,paint);

	//画切线
	nConPointNum = 0;
	path.moveTo(pt[0]);
	path.lineTo(ptCon[nConPointNum++]);
	for (int i = 1; i < nPointNum-1; i++)
	{
		path.moveTo(pt[i]);
		path.lineTo(ptCon[nConPointNum++]);
		path.moveTo(pt[i]);
		path.lineTo(ptCon[nConPointNum++]);
	}
	path.moveTo(pt[nPointNum-1]);
	path.lineTo(ptCon[nConPointNum++]);
	canvas->drawPath(path,paint);

	delete [] v_pt;
	delete ptCon;
	delete pt;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值