第5章,[Win32 章节] :贝塞尔样条曲线(一)
专栏导航上一篇第5章[Win32 章节] 边框绘制函数的教材案例回到目录下一篇第5章[Win32 章节] 贝塞尔样条曲线二本节前言对于本节所讲解的知识有可能你会需要时不时地参考本专栏的其它文章。真的遇到了需要参考之前的文章的知识点请你自行查阅。我呢也会提到一部分的参考课节。但是呢你不应该依赖于我的主动提及。最好呢你自己能够多去了解和查看本专栏目录。关于贝塞尔曲线最初我是在学习 3ds max 的时候接触到了它。后来呢我在学习 PhotoShop 软件的时候又一次接触了它。没想到后来在学习 Windows API 编程的时候再一次学习了它。在 PhotoShop 里面用钢笔工具绘制出来的曲线便是贝塞尔样条曲线。没有学过 PhotoShop 的话那么你依然可以跟着佩措尔德的教材来学习这个东西。本节内容来自于对佩措尔德教材的大段抄录。一. 本节内容英文单词 “spline”曲尺又称为样条曲线最初指的是一块可以弯曲的物体可以是木头、橡皮或者金属条它可以用来在纸张上绘制曲线。例如如果有一些离散的点并且想在它们之间画曲线无论是内插拟合还是外插拟合都应当首先将这些点描绘在图纸上。接着固定一个曲尺在这些点上使用铅笔沿着曲尺绕着这些点弯曲的方向绘制曲线。当然现在样条曲线已经变成了一个个数学公式。有很多种不同的样条曲线但是贝塞尔样条曲线是计算机图形程序设计中用得最广的。它是后来才加到操作系统的图形工具库中并且它出自一个几乎不可能的来源20 世纪 60 年代法国雷诺汽车公司由手工设计车体使用粘土模型转变到使用计算机辅助设计。这就需要用到一些数学工具而皮埃尔·贝济埃Pierre Bezier提出了一套数学公式事实证明这些数学公式起到了很大的作用。从那时起二维的贝塞尔样条曲线被认为是在计算机图形学中最有用的曲线之一仅次于直线和椭圆。在 PostScript 中贝塞尔样条曲线用于所有的曲线甚至椭圆也由贝塞尔样条曲线来近似。PostScript 字体的字符轮廓的定义也使用贝塞尔样条曲线定义。TrueType 则使用另外一种相对简单快速的样条曲线公式。一条二维贝塞尔样条曲线使用四个点来定义两个端点和两个控点。两个端点表示曲线的起点和终点。控点就好像磁铁一样把曲线从两个端点间的直线处吸弯。对此下述程序所示的 Bezier 交互式程序便是一个好的例证。/*--------------------------------------- BEZIER.C -- Bezier Splines Demo (c) Charles Petzold, 1998 水饺编程改编2026 ---------------------------------------*/ #include windows.h LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] TEXT(Bezier); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc WndProc; wndclass.cbClsExtra 0; wndclass.cbWndExtra 0; wndclass.hInstance hInstance; wndclass.hIcon LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName NULL; wndclass.lpszClassName szAppName; if (!RegisterClass(wndclass)) { MessageBox(NULL, TEXT(注册窗口类失败), szAppName, MB_ICONERROR); return 0; } hwnd CreateWindow(szAppName, TEXT(Bezier Splines), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(msg, NULL, 0, 0)) { TranslateMessage(msg); DispatchMessage(msg); } return msg.wParam; } void DrawBezier(HDC hdc, POINT apt[], BOOL flag_eraser) { HPEN hPen, hOldPen; COLORREF color; hPen hOldPen NULL; PolyBezier(hdc, apt, 4); if (TRUE flag_eraser) { color RGB(255, 0, 0); hPen CreatePen(PS_DASH, 1, color); hOldPen (HPEN)SelectObject(hdc, hPen); } MoveToEx(hdc, apt[0].x, apt[0].y, NULL); LineTo(hdc, apt[1].x, apt[1].y); MoveToEx(hdc, apt[2].x, apt[2].y, NULL); LineTo(hdc, apt[3].x, apt[3].y); if (TRUE flag_eraser) { SelectObject(hdc, hOldPen); DeleteObject(hPen); } } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static POINT apt[4]; HDC hdc; int cxClient, cyClient; PAINTSTRUCT ps; switch (message) { case WM_SIZE: cxClient LOWORD(lParam); cyClient HIWORD(lParam); apt[0].x cxClient / 4; apt[0].y cyClient / 2; apt[1].x cxClient / 2; apt[1].y cyClient / 4; apt[2].x cxClient / 2; apt[2].y 3 * cyClient / 4; apt[3].x 3 * cxClient / 4; apt[3].y cyClient / 2; return 0; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MOUSEMOVE: if (wParam MK_LBUTTON || wParam MK_RBUTTON) { hdc GetDC(hwnd); SelectObject(hdc, GetStockObject(WHITE_PEN)); DrawBezier(hdc, apt, FALSE); if (wParam MK_LBUTTON) { apt[1].x LOWORD(lParam); apt[1].y HIWORD(lParam); } if (wParam MK_RBUTTON) { apt[2].x LOWORD(lParam); apt[2].y HIWORD(lParam); } SelectObject(hdc, GetStockObject(BLACK_PEN)); DrawBezier(hdc, apt, TRUE); ReleaseDC(hwnd, hdc); } return 0; case WM_PAINT: InvalidateRect(hwnd, NULL, TRUE); hdc BeginPaint(hwnd, ps); DrawBezier(hdc, apt, TRUE); EndPaint(hwnd, ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }对于上述代码块中的代码你暂时不需要理解。因为它涉及了以后的章节才会讲到的鼠标消息的处理方法。此时你只需要能够将其编译出来并且在运行过程中了解这个程序的使用方法和运行效果就可以了。程序编译和运行这种纯软件操作的问题如果你忘了可以参考下述文章。参考课节使用 VS2010 编写 C语言程序参考课节用 VS2019 编写C语言程序本节程序主要的代码逻辑都是佩措尔德原教材的代码逻辑。但是呢我也改动了一部分代码逻辑。程序运行的结果如下图所示。图1图1 所示为默认的运行结果。注意在图1 中黑色实线的部分才是贝塞尔曲线。红色虚线的部分它并不是贝塞尔曲线而是辅助线。程序运行起来以后你可以通过鼠标左键单击和左键拖动的操作来改变第一个控点的位置从而影响整体的贝塞尔曲线的形状。你也可以通过鼠标右键的单击和右键拖动来改变第二个控点的位置从而影响整体的贝塞尔曲线的形状。我相信你很快地就能够理解大致的操作方式。这个程序我当初在学习的时候我觉得它是一个很好玩的程序。在我这里我在运行了程序以后没有改变第一个控点的位置而是选择去改变第二个控点的位置。形成的图形如下所示。图2除了绘制贝塞尔样条曲线本身程序还从第一个控点向左边的第一个端点也就是起点画直线并从第二个控点向右边的端点画直线。由控点向端点绘制的直线属于是辅助线。我将这个辅助线用虚线来绘制。用虚线来画线条同样是涉及了在以后的章节内容中才会讲到的知识。默认地在客户区中绘制线条采用的是实线。我们也可以用虚线来绘制线条。想要用虚线来画线我们需要用到的是画笔知识。画笔知识本章的后面我们就会讲到。此刻你有个数就行。程序中有关于画笔的使用你暂时应该是还看不懂涉及画笔的代码。所以再次强调本节程序你暂时不需要阅读其中的代码更不需要掌握其中的代码逻辑。暂时地你只需要能够将本节程序编译出来运行它掌握使用方法这就够了。至于说想要很好地理解本节程序代码你需要学习完本章后面会讲到的画笔知识也需要学习完以后的章节中会讲到的鼠标消息知识你才能看懂本节程序代码。结束语本节就先到这里了。下一节我们接着讲贝塞尔样条曲线。专栏导航上一篇第5章[Win32 章节] 边框绘制函数的教材案例回到目录下一篇第5章[Win32 章节] 贝塞尔样条曲线二

相关新闻

第05章 内核代码(11):操作系统的“心脏起搏器”——深度拆解 sched.c 的调度、睡眠与唤醒魔法

第05章 内核代码(11):操作系统的“心脏起搏器”——深度拆解 sched.c 的调度、睡眠与唤醒魔法

免责声明 本文内容仅限技术学习与交流使用。文中涉及的代码、算法及数据结构基于 1991 年的 Linux 0.11 内核源代码。当前主流 Linux 内核(如 2.6.x 及以上)的调度器(如 CFS 完全公平调度器)与 0.11 基于时间片轮转的调度算法已完全不同,若尝试将文中所述逻辑直接迁移至现…

2026/10/25 10:24:20 阅读更多 →
第05章 内核代码(12):调度中枢的灵魂剖析——逐行拆解 sched.c 的进程管理、睡眠唤醒与时间脉搏

第05章 内核代码(12):调度中枢的灵魂剖析——逐行拆解 sched.c 的进程管理、睡眠唤醒与时间脉搏

免责声明 本文内容仅限技术学习与交流使用。文中涉及的代码、数据结构及算法基于 1991 年的 Linux 0.11 内核源代码。现代 Linux 内核(2.6.x 及以上)的调度器(CFS)、睡眠机制(等待队列)和同步原语(互斥锁)已发生翻天覆地的变化。若将文中所述的早期代码逻辑直接迁移至当…

2026/10/25 2:43:33 阅读更多 →
腾讯科恩实验室 一面 四

腾讯科恩实验室 一面 四

目录一、DeepSeek-R1 的思维链(CoT)原理1.1 思维链到底是什么1.2 DeepSeek-R1 是怎么"学会思考"的1.3 思维链的本质:三个关键特征1.4 信息论视角:CoT 为什么有效1.5 架构支撑:MoE 混合专家1.6 解码策略的严谨…

2026/11/1 17:08:18 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/14 5:13:29 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/14 5:13:29 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/14 5:13:29 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/13 22:08:41 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/14 2:41:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/14 5:13:29 阅读更多 →

日新闻

周新闻

月新闻