解析在Direct2D中画Bezier曲线的实现方法
方法 实现 解析 曲线
2023-06-13 09:14:54 时间
DrawaSmoothCurvethroughaSetof2DPointswithBezierPrimitives
///<summary>
///Referto:http://www.codeproject.com/KB/graphics/BezierSpline.aspx
///Solvesatridiagonalsystemforoneofcoordinates(xory)offirstBeziercontrolpoints.
///</summary>
///<paramname="rhs">Righthandsidevector.</param>
///<paramname="x">Solutionvector.</param>
voidGetFirstControlPoints(
__inconststd::vector<FLOAT>&rhs,
__outstd::vector<FLOAT>&x)
{
ATLASSERT(rhs.size()==x.size());
intn=rhs.size();
std::vector<FLOAT>tmp(n); //Tempworkspace.
FLOATb=2.0f;
x[0]=rhs[0]/b;
for(inti=1;i<n;i++)//Decompositionandforwardsubstitution.
{
tmp[i]=1/b;
b=(i<n-1?4.0f:3.5f)-tmp[i];
x[i]=(rhs[i]-x[i-1])/b;
}
for(inti=1;i<n;i++)
{
x[n-i-1]-=tmp[n-i]*x[n-i];//Backsubstitution.
}
}
///<summary>
///Referto:http://www.codeproject.com/KB/graphics/BezierSpline.aspx
///Getopen-endedBezierSplineControlPoints.
///</summary>
///<paramname="knots">InputKnotBeziersplinepoints.</param>
///<paramname="firstCtrlPt">OutputFirstControlpointsarrayofknots.size()-1length.</param>
///<paramname="secondCtrlPt">OutputSecondControlpointsarrayofknots.size()-1length.</param>
voidGetCurveControlPoints(
__inconststd::vector<D2D1_POINT_2F>&knots,
__outstd::vector<D2D1_POINT_2F>&firstCtrlPt,
__outstd::vector<D2D1_POINT_2F>&secondCtrlPt)
{
ATLASSERT((firstCtrlPt.size()==secondCtrlPt.size())
&&(knots.size()==firstCtrlPt.size()+1));
intn=knots.size()-1;
ATLASSERT(n>=1);
if(n==1)
{
//Specialcase:Beziercurveshouldbeastraightline.
//3P1=2P0+P3
firstCtrlPt[0].x=(2*knots[0].x+knots[1].x)/3.0f;
firstCtrlPt[0].y=(2*knots[0].y+knots[1].y)/3.0f;
//P2=2P1?P0
secondCtrlPt[0].x=2*firstCtrlPt[0].x-knots[0].x;
secondCtrlPt[0].y=2*firstCtrlPt[0].y-knots[0].y;
return;
}
//CalculatefirstBeziercontrolpoints
//Righthandsidevector
std::vector<FLOAT>rhs(n);
//SetrighthandsideXvalues
for(inti=1;i<(n-1);++i)
{
rhs[i]=4*knots[i].x+2*knots[i+1].x;
}
rhs[0]=knots[0].x+2*knots[1].x;
rhs[n-1]=(8*knots[n-1].x+knots[n].x)/2.0f;
//GetfirstcontrolpointsX-values
std::vector<FLOAT>x(n);
GetFirstControlPoints(rhs,x);
//SetrighthandsideYvalues
for(inti=1;i<(n-1);++i)
{
rhs[i]=4*knots[i].y+2*knots[i+1].y;
}
rhs[0]=knots[0].y+2*knots[1].y;
rhs[n-1]=(8*knots[n-1].y+knots[n].y)/2.0f;
//GetfirstcontrolpointsY-values
std::vector<FLOAT>y(n);
GetFirstControlPoints(rhs,y);
//Filloutputarrays.
for(inti=0;i<n;++i)
{
//Firstcontrolpoint
firstCtrlPt[i]=D2D1::Point2F(x[i],y[i]);
//Secondcontrolpoint
if(i<(n-1))
{
secondCtrlPt[i]=D2D1::Point2F(2*knots[i+1].x-x[i+1],2*knots[i+1].y-y[i+1]);
}
else
{
secondCtrlPt[i]=D2D1::Point2F((knots[n].x+x[n-1])/2,(knots[n].y+y[n-1])/2);
}
}
}
HRESULTCreateBezierSpline(
__inID2D1Factory*pD2dFactory,
__inconststd::vector<D2D1_POINT_2F>&points,
__outID2D1PathGeometry**ppPathGeometry)
{
CHECK_PTR(pD2dFactory);
CHECK_OUTPUT_PTR(ppPathGeometry);
ATLASSERT(points.size()>1);
intn=points.size();
std::vector<D2D1_POINT_2F>firstCtrlPt(n-1);
std::vector<D2D1_POINT_2F>secondCtrlPt(n-1);
GetCurveControlPoints(points,firstCtrlPt,secondCtrlPt);
HRESULThr=pD2dFactory->CreatePathGeometry(ppPathGeometry);
CHECKHR(hr);
if(FAILED(hr))
returnhr;
CComPtr<ID2D1GeometrySink>spSink;
hr=(*ppPathGeometry)->Open(&spSink);
CHECKHR(hr);
if(SUCCEEDED(hr))
{
spSink->SetFillMode(D2D1_FILL_MODE_WINDING);
spSink->BeginFigure(points[0],D2D1_FIGURE_BEGIN_FILLED);
for(inti=1;i<n;i++)
spSink->AddBezier(D2D1::BezierSegment(firstCtrlPt[i-1],secondCtrlPt[i-1],points[i]));
spSink->EndFigure(D2D1_FIGURE_END_OPEN);
spSink->Close();
}
returnhr;
}
下面是一个使用此函数绘制正弦函数的Sample,曲线的红点是曲线的控制点:
#pragmaonce
#include"stdafx.h"
#include<Direct2DHelper.h>
usingD2D1::Point2F;
usingD2D1::SizeU;
usingD2D1::ColorF;
usingD2D1::Matrix3x2F;
usingD2D1::BezierSegment;
usingD2D1::RectF;
#include<vector>
usingstd::vector;
#include<algorithm>
#include<boost/math/distributions/normal.hpp>
classCMainWindow:
publicCWindowImpl<CMainWindow,CWindow,CSimpleWinTraits>
{
public:
BEGIN_MSG_MAP(CMainWindow)
MSG_WM_PAINT(OnPaint)
MSG_WM_ERASEBKGND(OnEraseBkgnd)
MSG_WM_SIZE(OnSize)
MSG_WM_CREATE(OnCreate)
MSG_WM_DESTROY(OnDestroy)
END_MSG_MAP()
intOnCreate(LPCREATESTRUCT/*lpCreateStruct*/)
{
CreateDeviceIndependentResource();
CreateDeviceResource();
CreateCurve();
return0;
}
voidOnDestroy()
{
PostQuitMessage(0);
}
voidOnPaint(CDCHandle)
{
CPaintDCdc(m_hWnd);
Render();
}
BOOLOnEraseBkgnd(CDCHandledc)
{
returnTRUE; //wehaveerasedthebackground
}
voidOnSize(UINT/*nType*/,CSizesize)
{
if(m_spHwndRT)
{
m_spHwndRT->Resize(SizeU(size.cx,size.cy));
CreateCurve();
}
}
private:
voidRender()
{
if(!m_spHwndRT)
CreateDeviceResource();
m_spHwndRT->BeginDraw();
m_spHwndRT->Clear(ColorF(ColorF::CornflowerBlue));
m_spHwndRT->SetTransform(Matrix3x2F::Identity());
D2D1_SIZE_Fsize=m_spHwndRT->GetSize();
FLOATwidth=size.width-50,height=size.height-50;
D2D1_MATRIX_3X2_FreflectY=Direct2DHelper::ReflectYMatrix();
D2D1_MATRIX_3X2_Ftranslate=Matrix3x2F::Translation(size.width/2.0f,size.height/2.0f);
m_spHwndRT->SetTransform(reflectY*translate);
//drawcoordinateaxis
m_spSolidBrush->SetColor(ColorF(ColorF::Red));
m_spHwndRT->DrawLine(Point2F(-width*0.5f,0),Point2F(width*0.5f,0),m_spSolidBrush,2.0f);
m_spSolidBrush->SetColor(ColorF(ColorF::DarkGreen));
m_spHwndRT->DrawLine(Point2F(0,-height*0.5f),Point2F(0,height*0.5f),m_spSolidBrush,2.0f);
//drawcurve
m_spSolidBrush->SetColor(ColorF(ColorF::Blue));
m_spHwndRT->DrawGeometry(m_spPathGeometry,m_spSolidBrush,1.0f);
//drawpointmarks
m_spSolidBrush->SetColor(ColorF(ColorF::Red));
for(autop=m_Points.cbegin();p!=m_Points.cend();p++)
{
Direct2DHelper::DrawRectPoint(m_spHwndRT,m_spSolidBrush,(*p),5.0f);
}
HRESULThr=m_spHwndRT->EndDraw();
if(hr==D2DERR_RECREATE_TARGET)
DiscardDeviceResource();
}
voidCreateDeviceIndependentResource()
{
Direct2DHelper::CreateD2D1Factory(&m_spD2dFactory);
}
voidCreateDeviceResource()
{
CRectrc;
GetClientRect(&rc);
CHECK_PTR(m_spD2dFactory);
IFR(m_spD2dFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(m_hWnd,SizeU(rc.Width(),rc.Height())),
&m_spHwndRT));
IFR(m_spHwndRT->CreateSolidColorBrush(ColorF(ColorF::Red),&m_spSolidBrush));
}
voidDiscardDeviceResource()
{
m_spSolidBrush.Release();
m_spHwndRT.Release();
}
voidCreateCurve()
{
if(!m_spHwndRT)
return;
if(m_spPathGeometry)
{
m_spPathGeometry.Release();
m_Points.clear();
}
constintptCount=100;
D2D1_SIZE_Fsize=m_spHwndRT->GetSize();
FLOATwidth=size.width-50.0f,height=size.height*0.4f;
#defineSIN_CURVE
#ifdefSIN_CURVE //createsincurve
FLOATfactor=static_cast<FLOAT>(4.0f*M_PI/width);
FLOATx=-width*0.5f,y=0,dx=width/ptCount;
for(inti=0;i<ptCount+1;i++)
{
y=height*sin(factor*x);
m_Points.push_back(Point2F(x,y));
x+=dx;
}
#else //createnormaldistributecurve
FLOATfactor=10.0f/width;
FLOATx=-width*0.5f,y=0,dx=width/ptCount;
boost::math::normalnd;
for(inti=0;i<ptCount+1;i++)
{
y=height*static_cast<FLOAT>(boost::math::pdf(nd,factor*x));
m_Points.push_back(Point2F(x,y));
x+=dx;
}
#endif//SIN_CURVE
//createBezierspline
Direct2DHelper::CreateBezierSpline(m_spD2dFactory,m_Points,&m_spPathGeometry);
CHECK_PTR(m_spPathGeometry);
}
private:
CComPtr<ID2D1Factory>m_spD2dFactory;
CComPtr<ID2D1HwndRenderTarget>m_spHwndRT;
CComPtr<ID2D1SolidColorBrush>m_spSolidBrush;
CComPtr<ID2D1PathGeometry>m_spPathGeometry;
vector<D2D1_POINT_2F>m_Points;
};
相关文章
- python敏感词过滤replace_python用类实现文章敏感词的过滤方法示例
- C++精通之路:红黑树的概念和实现方法的解析
- 详解Linux系统添加静态路由不通实现方法解析
- python多线程有几种实现方法详解编程语言
- Linux下XML解析的实现方法(linux解析xml)
- 串Linux实现字符串替换的方法(linux替换字符)
- Linux下域名本地解析实现方法(linux域名本地解析)
- 安装实现Linux系统自由定制:字体库安装方法(linux系统字体库)
- Linux下的域名泛解析实现方法(linux域名泛解析)
- MySQL中安全快捷删除大数据的方法(mysql删除大数据)
- 深度解析redis的hash结构:使用方法与实现原理(redis的hash结构)
- Redis轻松实现数据获取,解析获取值的方法(redis获取值)
- 了解 SQLServer 序列的用途和实现方法(sqlserver序列)
- Linux驱动程序中使用结构体的重要性与实现方法(linux驱动结构体)
- 深入了解Linux挂载概念:解析挂载的基本概念和实现方法(linux挂载概念)
- 实现数据共享MySQL 两表数据同步方法解析(mysql 两表同步数据)
- 打开超链需要“确认”对话框的方法
- 实现png图片和png背景透明(支持多浏览器)的方法
- android+json+php+mysql实现用户反馈功能方法解析
- nginx平滑重启与升级的实现方法
- 使用Java实现简单的server/client回显功能的方法介绍
- 解析WPF实现音频文件循环顺序播放的解决方法
- 解析在WTL下使用双缓冲的实现方法
- 解析Java实现随机验证码功能的方法详解
- 解析bitmap处理海量数据及其实现方法分析
- 解析如何用两个栈来实现队列的方法
- 解析MSSQL跨数据库查询的实现方法
- 解析CI的AJAX分页另类实现方法
- 解析PHP实现下载文件的两种方法
- python实现dnspod自动更新dns解析的方法
- python实现网页链接提取的方法分享
- destoon实现调用当前栏目分类及子分类和三级分类的方法