|
C++实现笔锋效果
实现笔锋的理论可参考网上的文章:
https://www.cnblogs.com/zl03jsj/p/8051912.html
https://www.cnblogs.com/zl03jsj/p/8048102.html
本文主要介绍如何编写代码实现书写时带笔锋的功能。
为了实现模块的分割和封装,我们首先建立一个动态库项目,并向项目中添加几个文件:
HandWriteHelp.h文件
- #pragma once
- #include <vector>
- #include "HandWriteMath.h"
- class HandWriteHelp
- {
- public:
- HandWriteHelp();
- ~HandWriteHelp();
- int startNewTrace()
- {
- pointArray = h_new_fpoint_array(24, 10, 1);
- return 0;
- }
- int addNewPoint(float x, float y,
- new_point_generated callback,//生成了新的点的回调
- void *context)
- {
- h_point pt;
- pt.x = x;
- pt.y = y;
- h_insert_point(pointArray, pt, callback, context);
- return 0;
- }
- int endCurrentTrace(float x, float y,
- new_point_generated callback,//生成了新的点的回调
- void *context)
- {
- h_point pt;
- pt.x = x;
- pt.y = y;
- h_insert_last_point(pointArray, pt, callback, context);
- h_drop_fpoint_array(pointArray);
- pointArray = NULL;
- return 0;
- }
- private:
- h_fpoint_array *pointArray;
- };
复制代码 HandWriteMath.h文件:
- #pragma once
- #include <stdint.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- typedef struct h_point_s h_point;
- typedef struct h_fpoint_s h_fpoint;
- typedef struct h_ipoint_s h_ipoint;
- typedef struct h_fpoint_array_s h_fpoint_array;
- typedef void(*new_point_generated)(float x, float y, float w, void* context);
- struct h_point_s {
- float x, y;
- };
- struct h_fpoint_s {
- h_point p;
- float w;
- };
- struct h_ipoint_s {
- h_point p;
- int64_t t;
- };
- struct h_fpoint_array_s {
- h_fpoint *point;
- float maxwidth;
- float minwidth;
- int ref;
- int len;
- int cap;
- h_point last_point;
- float last_width;
- int64_t last_ms;
- };
- h_fpoint_array *h_keep_fpoint_array(h_fpoint_array *a);
- void h_drop_fpoint_array(h_fpoint_array *a);
- h_fpoint_array *h_new_fpoint_array(int initsize, float maxwidth, float minwidth);
- h_fpoint_array *h_resize_fpoints_array(h_fpoint_array* a, int size);
- float h_movespeed(h_ipoint s, h_ipoint e);
- float h_distance(h_point s, h_point e);
- void h_fpoint_add_xyw(h_fpoint_array *a, float x, float y, float w);
- void h_fpoint_add(h_fpoint_array *a, h_fpoint p);
- void h_fpoint_differential_add(h_fpoint_array *a, h_fpoint p);
- void h_square_bezier(h_fpoint_array *a, h_fpoint b, h_point c, h_fpoint e);
- float h_linewidth(h_ipoint b, h_ipoint e, float w, float step);
- float h_insert_point(h_fpoint_array *arr, h_point point,
- new_point_generated callback, void *context);
- void h_insert_last_point(h_fpoint_array *arr, h_point e,
- new_point_generated callback, void *context);
- #ifdef __cplusplus
- }
- #endif
复制代码 HandWritLib.h文件:
- #ifndef HandWrite_h_
- #define HandWrite_h_
- #ifdef HANDWRITE_EXPORT
- #define DLL_EXPORT __declspec(dllexport)
- #else
- #define DLL_EXPORT __declspec(dllimport)
- #endif
- #ifdef __cplusplus
- extern "C" {
- #endif
- struct HandWritPoint {
- float x;
- float y;
- float w;
- };
- typedef void(*new_point_generated)(float x, float y, float w, void* context);
- //获取手写处理器
- DLL_EXPORT void* getHandWriteHelp();
- //释放手写处理器
- DLL_EXPORT void releaseHandWriteHelp(void** handWriter);
- //开始一次笔迹生成
- DLL_EXPORT int startNewTrace(void * handWriter);
- //增加一个书写点
- DLL_EXPORT int addNewPoint(float x, float y, void * handWriter,
- new_point_generated callback,//生成了新的点的回调
- void *context);//当前上下文,回调函数会传回来
- //输入最后一个点
- DLL_EXPORT int endCurrentTrace(float x, float y, void * handWriter,
- new_point_generated callback,//生成了新的点的回调
- void *context);
- #ifdef __cplusplus
- }
- #endif
- #endif
复制代码 HandWriteHelp.cpp文件:
- [hide]<div class="blockcode"><blockquote>#include "HandWriteHelp.h"
- HandWriteHelp::HandWriteHelp()
- {
- }
- HandWriteHelp::~HandWriteHelp()
- {
- }
复制代码 [/hide]
HandWriteLib.cpp文件:
HandWriteMath.c文件:
然后编译这个动态库项目,生成lib文件和dll文件, 编译动态库时预定义HANDWRITE_EXPORT宏。
然后我们新建一个基于对话框的MFC程序,项目中导入上面的lib文件,HandWriteLib.h头文件,dll文件也放到exe目录下。
对话框的代码如下:
对话框的头文件:
- // HandWritingDlg.h: 头文件
- //
- #pragma once
- #include "HandWritLib.h"
- #include <vector>
- #define WM_RCV_NEWPOINT (WM_USER + 100)
- #define MAX_WIDTH 10
- class CFPoint
- {
- public:
- float x;
- float y;
- CFPoint()
- {
- x = 0;
- y = 0;
- }
- CFPoint(float _x, float _y)
- {
- x = _x;
- y = _y;
- }
- CFPoint(const CFPoint &pt)
- {
- x = pt.x;
- y = pt.y;
- }
- inline CFPoint operator-(const CFPoint &initPt)
- {
- return CFPoint(x - initPt.x, y - initPt.y);
- }
- inline CFPoint operator+(const CFPoint &initPt)
- {
- return CFPoint(x + initPt.x, y + initPt.y);
- }
- inline CFPoint operator*(float value)
- {
- return CFPoint(x*value, y*value);
- }
- };
- // CHandWritingDlg 对话框
- class CHandWritingDlg : public CDialogEx
- {
- // 构造
- public:
- CHandWritingDlg(CWnd* pParent = nullptr); // 标准构造函数
- // 对话框数据
- #ifdef AFX_DESIGN_TIME
- enum { IDD = IDD_HANDWRITING_DIALOG };
- #endif
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
- // 实现
- protected:
- HICON m_hIcon;
- // 生成的消息映射函数
- virtual BOOL OnInitDialog();
- afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
- afx_msg void OnPaint();
- afx_msg HCURSOR OnQueryDragIcon();
- afx_msg HRESULT rcvNewPoint(WPARAM wParam, LPARAM lParam);
- DECLARE_MESSAGE_MAP()
- public:
- afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
- public:
- afx_msg void OnBnClickedButton1();
- void drawLine(const CFPoint &b, const CFPoint &e, int lineWidth);
- afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
- afx_msg void OnMouseMove(UINT nFlags, CPoint point);
- private:
- //是否开始生成
- bool isStartWrite;
- long lastPointTime;
- std::vector<HandWritPoint> lastPoint;
- void *handWriter;
- public:
- afx_msg void OnClose();
- afx_msg void OnDestroy();
- };
复制代码 对话框的cpp文件如下:
- // HandWritingDlg.cpp: 实现文件
- //
- #include "stdafx.h"
- #include "HandWriting.h"
- #include "HandWritingDlg.h"
- #include "afxdialogex.h"
- #include <algorithm>
- #include <vector>
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif
- // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
- class CAboutDlg : public CDialogEx
- {
- public:
- CAboutDlg();
- // 对话框数据
- #ifdef AFX_DESIGN_TIME
- enum { IDD = IDD_ABOUTBOX };
- #endif
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
- // 实现
- protected:
- DECLARE_MESSAGE_MAP()
- };
- CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
- {
- }
- void CAboutDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialogEx::DoDataExchange(pDX);
- }
- BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
-
- END_MESSAGE_MAP()
- // CHandWritingDlg 对话框
- CHandWritingDlg::CHandWritingDlg(CWnd* pParent /*=nullptr*/)
- : CDialogEx(IDD_HANDWRITING_DIALOG, pParent)
- {
- m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
- }
- void CHandWritingDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialogEx::DoDataExchange(pDX);
- }
- BEGIN_MESSAGE_MAP(CHandWritingDlg, CDialogEx)
- ON_WM_SYSCOMMAND()
- ON_WM_PAINT()
- ON_WM_QUERYDRAGICON()
- ON_WM_LBUTTONUP()
- ON_BN_CLICKED(IDC_BUTTON1, &CHandWritingDlg::OnBnClickedButton1)
- ON_WM_LBUTTONDOWN()
- ON_WM_MOUSEMOVE()
- ON_MESSAGE(WM_RCV_NEWPOINT, &CHandWritingDlg::rcvNewPoint)
- ON_WM_CLOSE()
- ON_WM_DESTROY()
- END_MESSAGE_MAP()
- // CHandWritingDlg 消息处理程序
- #include <math.h>
- BOOL CHandWritingDlg::OnInitDialog()
- {
- CDialogEx::OnInitDialog();
- // 将“关于...”菜单项添加到系统菜单中。
- // IDM_ABOUTBOX 必须在系统命令范围内。
- ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
- ASSERT(IDM_ABOUTBOX < 0xF000);
- CMenu* pSysMenu = GetSystemMenu(FALSE);
- if (pSysMenu != nullptr)
- {
- BOOL bNameValid;
- CString strAboutMenu;
- bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
- ASSERT(bNameValid);
- if (!strAboutMenu.IsEmpty())
- {
- pSysMenu->AppendMenu(MF_SEPARATOR);
- pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
- }
- }
- // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
- // 执行此操作
- SetIcon(m_hIcon, TRUE); // 设置大图标
- SetIcon(m_hIcon, FALSE); // 设置小图标
- handWriter = getHandWriteHelp();
- return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
- }
- void CHandWritingDlg::OnSysCommand(UINT nID, LPARAM lParam)
- {
- if ((nID & 0xFFF0) == IDM_ABOUTBOX)
- {
- CAboutDlg dlgAbout;
- dlgAbout.DoModal();
- }
- else
- {
- CDialogEx::OnSysCommand(nID, lParam);
- }
- }
- // 如果向对话框添加最小化按钮,则需要下面的代码
- // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
- // 这将由框架自动完成。
- void CHandWritingDlg::OnPaint()
- {
- if (IsIconic())
- {
- CPaintDC dc(this); // 用于绘制的设备上下文
- SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
- // 使图标在工作区矩形中居中
- int cxIcon = GetSystemMetrics(SM_CXICON);
- int cyIcon = GetSystemMetrics(SM_CYICON);
- CRect rect;
- GetClientRect(&rect);
- int x = (rect.Width() - cxIcon + 1) / 2;
- int y = (rect.Height() - cyIcon + 1) / 2;
- // 绘制图标
- dc.DrawIcon(x, y, m_hIcon);
- }
- else
- {
- CDialogEx::OnPaint();
- }
- }
- //当用户拖动最小化窗口时系统调用此函数取得光标
- //显示。
- HCURSOR CHandWritingDlg::OnQueryDragIcon()
- {
- return static_cast<HCURSOR>(m_hIcon);
- }
- void CHandWritingDlg::drawLine(const CFPoint &b, const CFPoint &e, int lineWidth)
- {
- CRect rect;
- CDC* pdc = this->GetDC();
- if (pdc == NULL)
- {
- DWORD dw = ::GetLastError();
- dw = dw;
- return;
- }
- Graphics graphics(pdc->m_hDC);
- graphics.SetSmoothingMode(SmoothingModeAntiAlias);
- graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
- static long drawtimes = 0;
- Pen pen(Color(255, 255, 0, 0), lineWidth);
- pen.SetStartCap(LineCapRound);
- pen.SetEndCap(LineCapRound);
- Gdiplus::Point points[2];
- points[0].X = b.x;
- points[0].Y = b.y;
- points[1].X = e.x;
- points[1].Y = e.y;
- graphics.DrawCurve(&pen, points, 2, 0.5);
- DeleteObject(pdc->m_hDC);
- }
- void newPointCallback(float x, float y, float w, void *context)
- {
- CHandWritingDlg *pThis = (CHandWritingDlg*)context;
- HandWritPoint *point = new HandWritPoint();
- point->x = x;
- point->y = y;
- point->w = w;
- pThis->SendMessage(WM_RCV_NEWPOINT, 0, (LPARAM)point);
- }
- void CHandWritingDlg::OnLButtonUp(UINT nFlags, CPoint point)
- {
- isStartWrite = false;
- endCurrentTrace(point.x, point.y, handWriter, newPointCallback, this);
- CDialogEx::OnLButtonUp(nFlags, point);
-
- }
- void CHandWritingDlg::OnBnClickedButton1()
- {
- lastPoint.clear();
- Invalidate();
- }
- HRESULT CHandWritingDlg::rcvNewPoint(WPARAM wParam, LPARAM lParam)
- {
- HandWritPoint *point = (HandWritPoint*)lParam;
- if (lastPoint.size() > 0)
- {
- HandWritPoint p = lastPoint.back();
- drawLine(CFPoint(p.x, p.y),
- CFPoint(point->x, point->y),
- MAX_WIDTH * (p.w) + 0.5);
- }
- lastPoint.push_back(*point);
- delete point;
- return 0;
- }
- void CHandWritingDlg::OnLButtonDown(UINT nFlags, CPoint point)
- {
- lastPoint.clear();
- startNewTrace(handWriter);
- addNewPoint(point.x, point.y, handWriter, newPointCallback, this);
- isStartWrite = true;
- CDialogEx::OnLButtonDown(nFlags, point);
- }
- void CHandWritingDlg::OnMouseMove(UINT nFlags, CPoint point)
- {
- if (isStartWrite == true)
- {
- addNewPoint(point.x, point.y, handWriter, newPointCallback, this);
- }
-
- CDialogEx::OnMouseMove(nFlags, point);
- }
- void CHandWritingDlg::OnClose()
- {
- // TODO: 在此添加消息处理程序代码和/或调用默认值
- CDialogEx::OnClose();
- }
- void CHandWritingDlg::OnDestroy()
- {
- CDialogEx::OnDestroy();
- // TODO: 在此处添加消息处理程序代码
- releaseHandWriteHelp(&handWriter);
- }
复制代码 程序运行的结果如下:
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|