一生一世学坛

 找回密码
 立即注册
搜索
查看: 7799|回复: 0
打印 上一主题 下一主题

Vc_C++实现笔锋效果代码实现

[复制链接]

334

主题

385

帖子

6816

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
6816
跳转到指定楼层
楼主
发表于 2019-3-30 18:12:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
C++实现笔锋效果
实现笔锋的理论可参考网上的文章:
https://www.cnblogs.com/zl03jsj/p/8051912.html
https://www.cnblogs.com/zl03jsj/p/8048102.html

本文主要介绍如何编写代码实现书写时带笔锋的功能。

为了实现模块的分割和封装,我们首先建立一个动态库项目,并向项目中添加几个文件:
HandWriteHelp.h文件
  1. #pragma once

  2. #include <vector>

  3. #include "HandWriteMath.h"

  4. class HandWriteHelp

  5. {

  6. public:

  7.         HandWriteHelp();

  8.         ~HandWriteHelp();

  9.         int startNewTrace()

  10.         {

  11.                 pointArray = h_new_fpoint_array(24, 10, 1);

  12.                 return 0;

  13.         }

  14.         int addNewPoint(float x, float y,

  15.                 new_point_generated  callback,//生成了新的点的回调

  16.                 void *context)

  17.         {

  18.                 h_point pt;

  19.                 pt.x = x;

  20.                 pt.y = y;

  21.                 h_insert_point(pointArray, pt, callback, context);

  22.                 return 0;

  23.         }

  24.         int endCurrentTrace(float x, float y,

  25.                 new_point_generated  callback,//生成了新的点的回调

  26.                 void *context)

  27.         {

  28.                 h_point pt;

  29.                 pt.x = x;

  30.                 pt.y = y;

  31.                 h_insert_last_point(pointArray, pt, callback, context);

  32.                 h_drop_fpoint_array(pointArray);

  33.                 pointArray = NULL;

  34.                 return 0;

  35.         }



  36. private:

  37.         h_fpoint_array *pointArray;

  38. };
复制代码
HandWriteMath.h文件:
  1. #pragma once
  2. #include <stdint.h>
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif

  6. typedef struct h_point_s  h_point;
  7. typedef struct h_fpoint_s h_fpoint;
  8. typedef struct h_ipoint_s h_ipoint;
  9. typedef struct h_fpoint_array_s h_fpoint_array;

  10. typedef void(*new_point_generated)(float x, float y, float w, void* context);

  11. struct h_point_s {
  12.         float x, y;
  13. };

  14. struct h_fpoint_s {
  15.         h_point p;
  16.         float w;
  17. };

  18. struct h_ipoint_s {
  19.         h_point p;
  20.         int64_t t;
  21. };

  22. struct h_fpoint_array_s {
  23.         h_fpoint *point;
  24.         float maxwidth;
  25.         float minwidth;
  26.         int ref;
  27.         int len;
  28.         int cap;

  29.         h_point last_point;
  30.         float last_width;
  31.         int64_t last_ms;
  32. };



  33. h_fpoint_array *h_keep_fpoint_array(h_fpoint_array *a);
  34. void h_drop_fpoint_array(h_fpoint_array *a);

  35. h_fpoint_array *h_new_fpoint_array(int initsize, float maxwidth, float minwidth);
  36. h_fpoint_array *h_resize_fpoints_array(h_fpoint_array* a, int size);


  37. float h_movespeed(h_ipoint s, h_ipoint e);
  38. float h_distance(h_point s, h_point e);
  39. void  h_fpoint_add_xyw(h_fpoint_array *a, float x, float y, float w);
  40. void  h_fpoint_add(h_fpoint_array *a, h_fpoint p);
  41. void  h_fpoint_differential_add(h_fpoint_array *a, h_fpoint p);
  42. void  h_square_bezier(h_fpoint_array *a, h_fpoint b, h_point c, h_fpoint e);
  43. float h_linewidth(h_ipoint b, h_ipoint e, float w, float step);

  44. float h_insert_point(h_fpoint_array *arr, h_point point,
  45.         new_point_generated  callback, void *context);
  46. void  h_insert_last_point(h_fpoint_array *arr, h_point e,
  47.         new_point_generated  callback, void *context);

  48. #ifdef __cplusplus
  49. }
  50. #endif
复制代码
HandWritLib.h文件:
  1. #ifndef HandWrite_h_
  2. #define HandWrite_h_
  3. #ifdef HANDWRITE_EXPORT
  4. #define DLL_EXPORT __declspec(dllexport)
  5. #else
  6. #define DLL_EXPORT __declspec(dllimport)
  7. #endif
  8. #ifdef __cplusplus
  9. extern "C" {
  10. #endif

  11. struct HandWritPoint {
  12.                 float x;
  13.                 float y;
  14.                 float w;
  15. };

  16. typedef void(*new_point_generated)(float x, float y, float w, void* context);

  17. //获取手写处理器
  18. DLL_EXPORT  void* getHandWriteHelp();

  19. //释放手写处理器
  20. DLL_EXPORT  void releaseHandWriteHelp(void** handWriter);

  21. //开始一次笔迹生成
  22. DLL_EXPORT int startNewTrace(void * handWriter);

  23. //增加一个书写点
  24. DLL_EXPORT int addNewPoint(float x, float y, void * handWriter,
  25.         new_point_generated  callback,//生成了新的点的回调
  26.         void *context);//当前上下文,回调函数会传回来

  27. //输入最后一个点
  28. DLL_EXPORT int endCurrentTrace(float x, float y, void * handWriter,
  29.         new_point_generated  callback,//生成了新的点的回调
  30.         void *context);


  31. #ifdef __cplusplus
  32. }
  33. #endif
  34. #endif
复制代码
HandWriteHelp.cpp文件:

  1. [hide]<div class="blockcode"><blockquote>#include "HandWriteHelp.h"



  2. HandWriteHelp::HandWriteHelp()
  3. {
  4. }


  5. HandWriteHelp::~HandWriteHelp()
  6. {
  7. }
复制代码
[/hide]

HandWriteLib.cpp文件:
游客,如果您要查看本帖隐藏内容请回复

HandWriteMath.c文件:
游客,如果您要查看本帖隐藏内容请回复


然后编译这个动态库项目,生成lib文件和dll文件,   编译动态库时预定义HANDWRITE_EXPORT宏。

然后我们新建一个基于对话框的MFC程序,项目中导入上面的lib文件,HandWriteLib.h头文件,dll文件也放到exe目录下。
对话框的代码如下:
对话框的头文件:

  1. // HandWritingDlg.h: 头文件
  2. //

  3. #pragma once

  4. #include "HandWritLib.h"
  5. #include <vector>

  6. #define WM_RCV_NEWPOINT (WM_USER + 100)
  7. #define MAX_WIDTH 10

  8. class CFPoint
  9. {
  10. public:
  11.         float x;
  12.         float y;

  13.         CFPoint()
  14.         {
  15.                 x = 0;
  16.                 y = 0;
  17.         }
  18.         CFPoint(float _x, float _y)
  19.         {
  20.                 x = _x;
  21.                 y = _y;
  22.         }
  23.         CFPoint(const CFPoint &pt)
  24.         {
  25.                 x = pt.x;
  26.                 y = pt.y;
  27.         }
  28.         inline CFPoint operator-(const CFPoint &initPt)
  29.         {
  30.                 return CFPoint(x - initPt.x, y - initPt.y);
  31.         }
  32.         inline CFPoint operator+(const CFPoint &initPt)
  33.         {
  34.                 return CFPoint(x + initPt.x, y + initPt.y);
  35.         }
  36.         inline CFPoint operator*(float value)
  37.         {
  38.                 return CFPoint(x*value, y*value);
  39.         }

  40. };

  41. // CHandWritingDlg 对话框
  42. class CHandWritingDlg : public CDialogEx
  43. {
  44. // 构造
  45. public:
  46.         CHandWritingDlg(CWnd* pParent = nullptr);        // 标准构造函数

  47. // 对话框数据
  48. #ifdef AFX_DESIGN_TIME
  49.         enum { IDD = IDD_HANDWRITING_DIALOG };
  50. #endif

  51.         protected:
  52.         virtual void DoDataExchange(CDataExchange* pDX);        // DDX/DDV 支持

  53. // 实现
  54. protected:
  55.         HICON m_hIcon;

  56.         // 生成的消息映射函数
  57.         virtual BOOL OnInitDialog();
  58.         afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
  59.         afx_msg void OnPaint();
  60.         afx_msg HCURSOR OnQueryDragIcon();

  61.         afx_msg HRESULT rcvNewPoint(WPARAM wParam, LPARAM lParam);

  62.         DECLARE_MESSAGE_MAP()
  63. public:
  64.         afx_msg void OnLButtonUp(UINT nFlags, CPoint point);


  65. public:
  66.         afx_msg void OnBnClickedButton1();
  67.         void drawLine(const CFPoint &b, const CFPoint &e, int lineWidth);
  68.         afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
  69.         afx_msg void OnMouseMove(UINT nFlags, CPoint point);
  70. private:

  71.         //是否开始生成
  72.         bool isStartWrite;
  73.         long lastPointTime;
  74.         std::vector<HandWritPoint> lastPoint;
  75.         void *handWriter;

  76. public:
  77.         afx_msg void OnClose();
  78.         afx_msg void OnDestroy();
  79. };
复制代码
对话框的cpp文件如下:

  1. // HandWritingDlg.cpp: 实现文件
  2. //

  3. #include "stdafx.h"
  4. #include "HandWriting.h"
  5. #include "HandWritingDlg.h"
  6. #include "afxdialogex.h"
  7. #include <algorithm>
  8. #include <vector>

  9. #ifdef _DEBUG
  10. #define new DEBUG_NEW
  11. #endif


  12. // 用于应用程序“关于”菜单项的 CAboutDlg 对话框

  13. class CAboutDlg : public CDialogEx
  14. {
  15. public:
  16.         CAboutDlg();

  17. // 对话框数据
  18. #ifdef AFX_DESIGN_TIME
  19.         enum { IDD = IDD_ABOUTBOX };
  20. #endif

  21.         protected:
  22.         virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

  23. // 实现
  24. protected:
  25.         DECLARE_MESSAGE_MAP()
  26. };

  27. CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
  28. {
  29. }

  30. void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  31. {
  32.         CDialogEx::DoDataExchange(pDX);
  33. }

  34. BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
  35.         
  36. END_MESSAGE_MAP()


  37. // CHandWritingDlg 对话框



  38. CHandWritingDlg::CHandWritingDlg(CWnd* pParent /*=nullptr*/)
  39.         : CDialogEx(IDD_HANDWRITING_DIALOG, pParent)
  40. {
  41.         m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  42. }

  43. void CHandWritingDlg::DoDataExchange(CDataExchange* pDX)
  44. {
  45.         CDialogEx::DoDataExchange(pDX);
  46. }

  47. BEGIN_MESSAGE_MAP(CHandWritingDlg, CDialogEx)
  48.         ON_WM_SYSCOMMAND()
  49.         ON_WM_PAINT()
  50.         ON_WM_QUERYDRAGICON()
  51.         ON_WM_LBUTTONUP()
  52.         ON_BN_CLICKED(IDC_BUTTON1, &CHandWritingDlg::OnBnClickedButton1)
  53.         ON_WM_LBUTTONDOWN()
  54.         ON_WM_MOUSEMOVE()
  55.         ON_MESSAGE(WM_RCV_NEWPOINT, &CHandWritingDlg::rcvNewPoint)
  56.         ON_WM_CLOSE()
  57.         ON_WM_DESTROY()
  58. END_MESSAGE_MAP()


  59. // CHandWritingDlg 消息处理程序
  60. #include <math.h>
  61. BOOL CHandWritingDlg::OnInitDialog()
  62. {
  63.         CDialogEx::OnInitDialog();

  64.         // 将“关于...”菜单项添加到系统菜单中。

  65.         // IDM_ABOUTBOX 必须在系统命令范围内。
  66.         ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  67.         ASSERT(IDM_ABOUTBOX < 0xF000);

  68.         CMenu* pSysMenu = GetSystemMenu(FALSE);
  69.         if (pSysMenu != nullptr)
  70.         {
  71.                 BOOL bNameValid;
  72.                 CString strAboutMenu;
  73.                 bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
  74.                 ASSERT(bNameValid);
  75.                 if (!strAboutMenu.IsEmpty())
  76.                 {
  77.                         pSysMenu->AppendMenu(MF_SEPARATOR);
  78.                         pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  79.                 }
  80.         }

  81.         // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
  82.         //  执行此操作
  83.         SetIcon(m_hIcon, TRUE);                        // 设置大图标
  84.         SetIcon(m_hIcon, FALSE);                // 设置小图标

  85.         handWriter = getHandWriteHelp();
  86.         return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
  87. }

  88. void CHandWritingDlg::OnSysCommand(UINT nID, LPARAM lParam)
  89. {
  90.         if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  91.         {
  92.                 CAboutDlg dlgAbout;
  93.                 dlgAbout.DoModal();
  94.         }
  95.         else
  96.         {
  97.                 CDialogEx::OnSysCommand(nID, lParam);
  98.         }
  99. }

  100. // 如果向对话框添加最小化按钮,则需要下面的代码
  101. //  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
  102. //  这将由框架自动完成。

  103. void CHandWritingDlg::OnPaint()
  104. {
  105.         if (IsIconic())
  106.         {
  107.                 CPaintDC dc(this); // 用于绘制的设备上下文

  108.                 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

  109.                 // 使图标在工作区矩形中居中
  110.                 int cxIcon = GetSystemMetrics(SM_CXICON);
  111.                 int cyIcon = GetSystemMetrics(SM_CYICON);
  112.                 CRect rect;
  113.                 GetClientRect(&rect);
  114.                 int x = (rect.Width() - cxIcon + 1) / 2;
  115.                 int y = (rect.Height() - cyIcon + 1) / 2;

  116.                 // 绘制图标
  117.                 dc.DrawIcon(x, y, m_hIcon);
  118.         }
  119.         else
  120.         {
  121.                 CDialogEx::OnPaint();
  122.         }
  123. }

  124. //当用户拖动最小化窗口时系统调用此函数取得光标
  125. //显示。
  126. HCURSOR CHandWritingDlg::OnQueryDragIcon()
  127. {
  128.         return static_cast<HCURSOR>(m_hIcon);
  129. }


  130. void CHandWritingDlg::drawLine(const CFPoint &b, const CFPoint &e, int lineWidth)
  131. {
  132.         CRect rect;
  133.         CDC* pdc = this->GetDC();
  134.         if (pdc == NULL)
  135.         {
  136.                 DWORD dw = ::GetLastError();
  137.                 dw = dw;
  138.                 return;
  139.         }

  140.         Graphics graphics(pdc->m_hDC);
  141.         graphics.SetSmoothingMode(SmoothingModeAntiAlias);
  142.         graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);

  143.         static long drawtimes = 0;
  144.         Pen pen(Color(255, 255, 0, 0), lineWidth);
  145.         pen.SetStartCap(LineCapRound);
  146.         pen.SetEndCap(LineCapRound);
  147.         Gdiplus::Point points[2];
  148.         points[0].X = b.x;
  149.         points[0].Y = b.y;
  150.         points[1].X = e.x;
  151.         points[1].Y = e.y;
  152.         graphics.DrawCurve(&pen, points, 2, 0.5);        
  153.         DeleteObject(pdc->m_hDC);
  154. }


  155. void newPointCallback(float x, float y, float w, void *context)
  156. {
  157.         CHandWritingDlg *pThis = (CHandWritingDlg*)context;
  158.         HandWritPoint *point = new HandWritPoint();
  159.         point->x = x;
  160.         point->y = y;
  161.         point->w = w;
  162.         pThis->SendMessage(WM_RCV_NEWPOINT, 0, (LPARAM)point);
  163. }


  164. void CHandWritingDlg::OnLButtonUp(UINT nFlags, CPoint point)
  165. {
  166.         isStartWrite = false;
  167.         endCurrentTrace(point.x, point.y, handWriter, newPointCallback, this);
  168.         CDialogEx::OnLButtonUp(nFlags, point);
  169.         
  170. }


  171. void CHandWritingDlg::OnBnClickedButton1()
  172. {
  173.         lastPoint.clear();
  174.         Invalidate();
  175. }

  176. HRESULT CHandWritingDlg::rcvNewPoint(WPARAM wParam, LPARAM lParam)
  177. {
  178.         HandWritPoint *point = (HandWritPoint*)lParam;

  179.         if (lastPoint.size() > 0)
  180.         {
  181.                 HandWritPoint p = lastPoint.back();
  182.                 drawLine(CFPoint(p.x, p.y),
  183.                         CFPoint(point->x, point->y),
  184.                         MAX_WIDTH * (p.w) + 0.5);

  185.         }
  186.         lastPoint.push_back(*point);
  187.         delete point;
  188.         return 0;
  189. }



  190. void CHandWritingDlg::OnLButtonDown(UINT nFlags, CPoint point)
  191. {
  192.         lastPoint.clear();
  193.         startNewTrace(handWriter);
  194.         addNewPoint(point.x, point.y, handWriter, newPointCallback, this);
  195.         isStartWrite = true;        
  196.         CDialogEx::OnLButtonDown(nFlags, point);
  197. }


  198. void CHandWritingDlg::OnMouseMove(UINT nFlags, CPoint point)
  199. {
  200.         if (isStartWrite == true)
  201.         {
  202.                 addNewPoint(point.x, point.y, handWriter, newPointCallback, this);
  203.         }
  204.         
  205.         CDialogEx::OnMouseMove(nFlags, point);
  206. }


  207. void CHandWritingDlg::OnClose()
  208. {
  209.         // TODO: 在此添加消息处理程序代码和/或调用默认值

  210.         CDialogEx::OnClose();
  211. }


  212. void CHandWritingDlg::OnDestroy()
  213. {
  214.         CDialogEx::OnDestroy();

  215.         // TODO: 在此处添加消息处理程序代码
  216.         releaseHandWriteHelp(&handWriter);
  217. }
复制代码
程序运行的结果如下:


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|分享学习  

GMT+8, 2024-5-2 15:01 , Processed in 0.046223 second(s), 5 queries , File On.

声明:本站严禁任何人以任何形式发表违法言论!

本站内容由网友原创或转载,如果侵犯了您的合法权益,请及时联系处理!© 2017 zamxqun@163.com

皖公网安备 34010402700634号

皖ICP备17017002号-1

快速回复 返回顶部 返回列表