//计算三次贝塞尔曲线,后面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;
}
绘制贝塞尔曲线通用方法
最新推荐文章于 2022-05-20 16:01:59 发布