├── BezierWave.pro
├── BezierWave.pro.user
├── LICENSE
├── README.md
├── bezierwavebean.cpp
├── bezierwavebean.h
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── mainwindow.ui
└── pictures
└── picture.gif
/BezierWave.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2019-05-31T12:01:22
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += core gui
8 |
9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10 |
11 | TARGET = BezierWave
12 | TEMPLATE = app
13 |
14 | # The following define makes your compiler emit warnings if you use
15 | # any feature of Qt which has been marked as deprecated (the exact warnings
16 | # depend on your compiler). Please consult the documentation of the
17 | # deprecated API in order to know how to port your code away from it.
18 | DEFINES += QT_DEPRECATED_WARNINGS
19 |
20 | # You can also make your code fail to compile if you use deprecated APIs.
21 | # In order to do so, uncomment the following line.
22 | # You can also select to disable deprecated APIs only up to a certain version of Qt.
23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
24 |
25 | CONFIG += c++11
26 |
27 | SOURCES += \
28 | main.cpp \
29 | mainwindow.cpp \
30 | bezierwavebean.cpp
31 |
32 | HEADERS += \
33 | mainwindow.h \
34 | bezierwavebean.h
35 |
36 | FORMS += \
37 | mainwindow.ui
38 |
39 | # Default rules for deployment.
40 | qnx: target.path = /tmp/$${TARGET}/bin
41 | else: unix:!android: target.path = /opt/$${TARGET}/bin
42 | !isEmpty(target.path): INSTALLS += target
43 |
--------------------------------------------------------------------------------
/BezierWave.pro.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | EnvironmentId
7 | {2a6768ec-1d4c-4eb5-99c7-39c6a5971fb8}
8 |
9 |
10 | ProjectExplorer.Project.ActiveTarget
11 | 0
12 |
13 |
14 | ProjectExplorer.Project.EditorSettings
15 |
16 | true
17 | false
18 | true
19 |
20 | Cpp
21 |
22 | CppGlobal
23 |
24 |
25 |
26 | QmlJS
27 |
28 | QmlJSGlobal
29 |
30 |
31 | 2
32 | UTF-8
33 | false
34 | 4
35 | false
36 | 80
37 | true
38 | true
39 | 1
40 | true
41 | false
42 | 0
43 | true
44 | true
45 | 0
46 | 8
47 | true
48 | 1
49 | true
50 | true
51 | true
52 | false
53 |
54 |
55 |
56 | ProjectExplorer.Project.PluginSettings
57 |
58 |
59 | true
60 |
61 |
62 |
63 | ProjectExplorer.Project.Target.0
64 |
65 | Desktop Qt 5.13.1 GCC 64bit
66 | Desktop Qt 5.13.1 GCC 64bit
67 | qt.qt5.5131.gcc_64_kit
68 | 0
69 | 0
70 | 0
71 |
72 | /home/mrxy001/Qt/build-BezierWave-Desktop_Qt_5_13_1_GCC_64bit-Debug
73 |
74 |
75 | true
76 | qmake
77 |
78 | QtProjectManager.QMakeBuildStep
79 | true
80 |
81 | false
82 | false
83 | false
84 |
85 |
86 | true
87 | Make
88 |
89 | Qt4ProjectManager.MakeStep
90 |
91 | false
92 |
93 |
94 | false
95 |
96 | 2
97 | Build
98 |
99 | ProjectExplorer.BuildSteps.Build
100 |
101 |
102 |
103 | true
104 | Make
105 |
106 | Qt4ProjectManager.MakeStep
107 |
108 | true
109 | clean
110 |
111 | false
112 |
113 | 1
114 | Clean
115 |
116 | ProjectExplorer.BuildSteps.Clean
117 |
118 | 2
119 | false
120 |
121 | Debug
122 | Debug
123 | Qt4ProjectManager.Qt4BuildConfiguration
124 | 2
125 | true
126 |
127 |
128 | /home/mrxy001/Qt/build-BezierWave-Desktop_Qt_5_13_1_GCC_64bit-Release
129 |
130 |
131 | true
132 | qmake
133 |
134 | QtProjectManager.QMakeBuildStep
135 | false
136 |
137 | false
138 | false
139 | true
140 |
141 |
142 | true
143 | Make
144 |
145 | Qt4ProjectManager.MakeStep
146 |
147 | false
148 |
149 |
150 | false
151 |
152 | 2
153 | Build
154 |
155 | ProjectExplorer.BuildSteps.Build
156 |
157 |
158 |
159 | true
160 | Make
161 |
162 | Qt4ProjectManager.MakeStep
163 |
164 | true
165 | clean
166 |
167 | false
168 |
169 | 1
170 | Clean
171 |
172 | ProjectExplorer.BuildSteps.Clean
173 |
174 | 2
175 | false
176 |
177 | Release
178 | Release
179 | Qt4ProjectManager.Qt4BuildConfiguration
180 | 0
181 | true
182 |
183 |
184 | /home/mrxy001/Qt/build-BezierWave-Desktop_Qt_5_13_1_GCC_64bit-Profile
185 |
186 |
187 | true
188 | qmake
189 |
190 | QtProjectManager.QMakeBuildStep
191 | true
192 |
193 | false
194 | true
195 | true
196 |
197 |
198 | true
199 | Make
200 |
201 | Qt4ProjectManager.MakeStep
202 |
203 | false
204 |
205 |
206 | false
207 |
208 | 2
209 | Build
210 |
211 | ProjectExplorer.BuildSteps.Build
212 |
213 |
214 |
215 | true
216 | Make
217 |
218 | Qt4ProjectManager.MakeStep
219 |
220 | true
221 | clean
222 |
223 | false
224 |
225 | 1
226 | Clean
227 |
228 | ProjectExplorer.BuildSteps.Clean
229 |
230 | 2
231 | false
232 |
233 | Profile
234 | Profile
235 | Qt4ProjectManager.Qt4BuildConfiguration
236 | 0
237 | true
238 |
239 | 3
240 |
241 |
242 | 0
243 | 部署
244 |
245 | ProjectExplorer.BuildSteps.Deploy
246 |
247 | 1
248 | Deploy Configuration
249 |
250 | ProjectExplorer.DefaultDeployConfiguration
251 |
252 | 1
253 |
254 |
255 | dwarf
256 |
257 | cpu-cycles
258 |
259 |
260 | 250
261 | -F
262 | true
263 | 4096
264 | false
265 | false
266 | 1000
267 |
268 | true
269 |
270 | false
271 | false
272 | false
273 | false
274 | true
275 | 0.01
276 | 10
277 | true
278 | kcachegrind
279 | 1
280 | 25
281 |
282 | 1
283 | true
284 | false
285 | true
286 | valgrind
287 |
288 | 0
289 | 1
290 | 2
291 | 3
292 | 4
293 | 5
294 | 6
295 | 7
296 | 8
297 | 9
298 | 10
299 | 11
300 | 12
301 | 13
302 | 14
303 |
304 | 2
305 |
306 | BezierWave
307 |
308 | Qt4ProjectManager.Qt4RunConfiguration:/home/mrxy001/Qt/Bezier-Wave/BezierWave.pro
309 |
310 | 3768
311 | false
312 | true
313 | true
314 | false
315 | false
316 | true
317 |
318 | /home/mrxy001/Qt/build-BezierWave-Desktop_Qt_5_13_1_GCC_64bit-Debug
319 |
320 | 1
321 |
322 |
323 |
324 | ProjectExplorer.Project.TargetCount
325 | 1
326 |
327 |
328 | ProjectExplorer.Project.Updater.FileVersion
329 | 22
330 |
331 |
332 | Version
333 | 22
334 |
335 |
336 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 贝塞尔曲线波浪
2 | ===
3 |
4 | ## 安装与运行环境
5 |
6 | - 语言:C++
7 | - 框架:Qt 11.3
8 | - 平台:Windows
9 |
10 | ## 截图
11 |
12 | 
13 |
14 | ## 算法
15 |
16 | 将屏幕水平平均分为10块,在一定范围内随机高度的12个点(左右出头),通过贝塞尔曲线连接连续的点,即可绘制成一段段连续的波浪。
17 |
18 | 但是每两端波浪都会有折线凸起,根据贝塞尔曲线的原理,两个控制点中点作为新的控制点,原来的两点连线即为该控制点在新曲线上的切线,这样既可绘制成只由三个控制点影响的`B样条`。
19 |
20 | 为了逼真,通过时钟以及大量状态机确定随机范围,例如在某一段时间整体偏下方,某一段时间整体偏上方,模仿大自然水面潮涨潮落。
21 |
22 | ## 用法
23 |
24 | 创建:
25 |
26 | ```C++
27 | MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
28 | {
29 | bw1 = new BezierWaveBean(this);
30 | bw1->set_offsety(geometry().height()/20); // 垂直偏移位置【可选】
31 | bw1->set_speedx(4); // 设置速度
32 | bw1->start();
33 | }
34 | ```
35 |
36 | 绘制:
37 |
38 | ```C++
39 | void MainWindow::paintEvent(QPaintEvent *e)
40 | {
41 | QPainter painter(this);
42 | painter.setRenderHint(QPainter::Antialiasing, true); // 抗锯齿
43 |
44 | painter.fillPath(bw1->getPainterPath(painter), QColor(255, 0, 0, 50));
45 |
46 | return QMainWindow::paintEvent(e);
47 | }
48 | ```
49 |
50 | 尺寸:
51 |
52 | ```C++
53 | void MainWindow::resizeEvent(QResizeEvent *e)
54 | {
55 | bw1->set_rect(geometry());
56 | return QMainWindow::resizeEvent(e);
57 | }
58 | ```
59 |
60 | 开关:
61 |
62 | ```C++
63 | bw1->start(); // 开始
64 | bw1->pause(); // 暂停
65 | bw1->resume(); // 继续
66 | ```
67 |
68 |
--------------------------------------------------------------------------------
/bezierwavebean.cpp:
--------------------------------------------------------------------------------
1 | #include "bezierwavebean.h"
2 |
3 | BezierWaveBean::BezierWaveBean(QWidget* parent) : QObject(parent), target(parent), mt(rd())
4 | {
5 | srand(static_cast(time(nullptr)));
6 |
7 | count = 8; // 点的总数
8 | inter = target->geometry().width()/(count-4);
9 | appear_speedy = 3; // 出现时的最大速度
10 |
11 | // speedy = appear_speedy; // y移动速度
12 | offsety = 0; // y累计偏移
13 | offsety_direct = -1; // y短期偏移方向,-1上 和 1下
14 | speedx = 3; // x移动速度
15 | offsetx = 0; // x累计偏移
16 |
17 | speedy_step = 3;
18 | _offsety = 0;
19 | _max_offsety = target->geometry().height()/10; // 上下最大偏移的位置(注意:效果是正负翻倍的)
20 | _rect = target->geometry();
21 | running = false;
22 |
23 | // 更新目标点的时钟:1.5秒钟左右
24 | update_timer = new QTimer(target);
25 | update_timer->setInterval(1000);
26 | connect(update_timer, SIGNAL(timeout()), this, SLOT(slotUpdateAims())); // 每隔一段时间更新一下位置
27 |
28 | // 移动波浪的时钟:40毫秒
29 | move_timer = new QTimer(this);
30 | move_timer->setInterval(getRandom(35, 45));
31 | connect(move_timer, SIGNAL(timeout()), this, SLOT(slotMovePoints()));
32 |
33 | // y偏移波浪的时钟:4秒左右
34 | offset_timer = new QTimer(this);
35 | offset_timer->setInterval(4000);
36 | connect(offset_timer, SIGNAL(timeout()), this, SLOT(slotSetOffset()));
37 |
38 | // 慢慢暂停的时钟
39 | pause_timer = new QTimer(this);
40 | pause_timer->setInterval(3000);
41 | connect(pause_timer, &QTimer::timeout, [=]{
42 | if (!running)
43 | {
44 | update_timer->stop();
45 | move_timer->stop();
46 | offset_timer->stop();
47 |
48 | for(int i = 0; i < keys.length(); i++)
49 | keys[i].setY(target->geometry().height());
50 | offsety = -_max_offsety/2; // 清空偏移(消失时默认都在最下面的,现在恢复)
51 | }
52 | });
53 | }
54 |
55 | void BezierWaveBean::start()
56 | {
57 | // 初始化一个值
58 | aim_keys.clear();
59 | keys.clear();
60 | speedys.clear();
61 | running = true;
62 | for (int i = 0; i < count; i++)
63 | aim_keys.append(QPoint(inter*(i-2), getRandomHeight()));
64 | for (int i = 0; i < aim_keys.length(); i++)
65 | keys.append(QPoint(aim_keys.at(i).x(), target->geometry().height()));
66 | for (int i = 0; i < aim_keys.length(); i++)
67 | speedys.append(- getRandom(appear_speedy * speedy_step / 2, appear_speedy * speedy_step));
68 | qint64 timestamp = getTimestamp();
69 | for (int i = 0; i < aim_keys.length(); i++)
70 | aim_updates_timestamp.append(timestamp);
71 |
72 | update_timer->start();
73 | move_timer->start();
74 | offset_timer->start();
75 |
76 | }
77 |
78 | void BezierWaveBean::resume()
79 | {
80 | if (keys.length() == 0)
81 | return start();
82 | if (running) return ; // 正在动画中,没必要
83 | update_timer->start();
84 | move_timer->start();
85 | offset_timer->start();
86 | pause_timer->stop();
87 | running = true;
88 | slotUpdateAims(); // 立即更新目标
89 | for (int i = 0; i < speedys.length(); i++)
90 | speedys[i] = appear_speedy * speedy_step;
91 | }
92 |
93 | void BezierWaveBean::pause()
94 | {
95 | running = false;
96 | for (int i = 0; i < aim_keys.length(); i++)
97 | aim_keys[i].setY(getRandomHeight());
98 | pause_timer->start();
99 | }
100 |
101 | void BezierWaveBean::set_count(int x)
102 | {
103 | if (x > 5)
104 | count = x;
105 | }
106 |
107 | void BezierWaveBean::set_offsety(int x)
108 | {
109 | _offsety = x;
110 | }
111 |
112 | void BezierWaveBean::set_speedx(int x)
113 | {
114 | speedx = x;
115 | }
116 |
117 | void BezierWaveBean::set_rect(QRect rect)
118 | {
119 | int delta = rect.height() - _rect.height();
120 | inter = rect.width() / (count - 4);
121 | for (int i = 0; i < keys.length(); i++)
122 | {
123 | // 修改所有点的间隔
124 | //keys[i].setX(keys.at(i).x() * width / _rect.width()); // 按比例缩放……
125 | keys[i].setX(inter*(i-2)+offsetx);
126 | aim_keys[i].setX(keys.at(i).x());
127 | // 修改整体的高度
128 | keys[i].setY(keys.at(i).y()+delta);
129 | aim_keys[i].setY(aim_keys.at(i).y()+delta);
130 | }
131 | double time = pow(rect.width(), 1.0 / 5); // 代表一个点显示几秒钟
132 | speedx = rect.width() / (1000 / move_timer->interval()) / time;
133 | _rect = rect;
134 | }
135 |
136 | QPainterPath BezierWaveBean::getPainterPath(QPainter& painter)
137 | {
138 | Q_UNUSED(painter)
139 |
140 | // 从关键点生成绘图点
141 | QListpots;
142 | for (int i = 0; i < keys.length(); i++)
143 | {
144 | if (i & 1) // 奇数
145 | {
146 | int x = (keys.at(i-1).x()+keys.at(i).x())/2;
147 | int y = (keys.at(i-1).y()+keys.at(i).y())/2;
148 | pots.append(QPoint(x, y));
149 | pots.append(keys.at(i));
150 | }
151 | else // 偶数
152 | pots.append(keys.at(i));
153 | }
154 |
155 | // y方向的偏移
156 | for (int i = 0; i < pots.length(); i++)
157 | {
158 | pots[i].setY(pots[i].y()+offsety);
159 | }
160 |
161 | // 画进行判断的点
162 | /*for (int i = 0; i < pots.length(); i++)
163 | {
164 | QPoint p = pots.at(i);
165 | painter.drawEllipse(QRect(p.x()-2, p.y()-2, 4, 4));
166 | }*/
167 |
168 | // 开始画图
169 | QPainterPath bezier;
170 | bezier.moveTo(0, target->geometry().height());
171 | bezier.lineTo(pots.at(1));
172 | //painter.drawLine(pots.at(0), pots.at(1));
173 | for (int i = 2; i+2 < pots.count(); i+=3)
174 | {
175 | // 画切线线条
176 | //painter.drawLine(pots.at(i-1), pots.at(i));
177 | //painter.drawLine(pots.at(i+1), pots.at(i+2));
178 |
179 | // 画三阶贝塞尔曲线
180 | bezier.cubicTo(pots.at(i), pots.at(i+1), pots.at(i+2));
181 | }
182 | bezier.lineTo(target->geometry().bottomRight());
183 |
184 | return bezier;
185 | }
186 |
187 |
188 | int BezierWaveBean::getRandomHeight()
189 | {
190 | if (running)
191 | {
192 | int y = getRandom(target->geometry().height() / 2, target->geometry().height() * 7 / 8);
193 | return y;
194 | }
195 | else
196 | return int(target->geometry().height()*1.5);
197 | }
198 |
199 | int BezierWaveBean::getRandom(int min, int max)
200 | {
201 | #if defined (Q_OS_WIN) || defined(Q_OS_LINUX)
202 | return mt() % (max-min+1) + min;
203 | #elif defined(Q_OS_MAC)
204 |
205 | #else
206 | return rand() % (max-min+1) + min;
207 | #endif
208 | }
209 |
210 | qint64 BezierWaveBean::getTimestamp()
211 | {
212 | return QDateTime::currentDateTime().toMSecsSinceEpoch();
213 | }
214 |
215 | void BezierWaveBean::slotUpdateAims()
216 | {
217 | if (!running) return ;
218 | /*for (int i = 0; i < speedys.length(); i++)
219 | if (speedys.at(i) == appear_speedy*speedy_step)
220 | speedys[i] = 1;*/
221 | // 生成随机的目标关键点
222 | int delta = target->geometry().height()/4;
223 | qint64 timestamp = getTimestamp();
224 | for (int i = 0; i < aim_keys.length(); i++)
225 | {
226 | if (aim_updates_timestamp.at(i) + 3000 > timestamp) // 3秒更新一次
227 | continue;
228 | int y = aim_keys.at(i).y() + getRandom(-delta, delta);
229 | if (y < target->geometry().height() / 2)
230 | y = target->geometry().height() / 2;
231 | else if (y > target->geometry().height()*7/8)
232 | y = target->geometry().height()*7/8;
233 | aim_keys[i].setY(y + _offsety);
234 | aim_updates_timestamp[i] = timestamp;
235 | }
236 | }
237 |
238 | void BezierWaveBean::slotMovePoints()
239 | {
240 | // Y方向慢慢移动当前关键点到目标关键点
241 | for (int i = 0; i < keys.length(); i++)
242 | {
243 | QPoint& cur = keys[i];
244 | QPoint aim = aim_keys[i];
245 | int del = aim.y()-cur.y();
246 | if (del > 0) // 应当往下移动
247 | {
248 | speedys[i]++; // 向下的加速度
249 | // speedys[i] += sqrt(del)/speedx/speedy_step+1;
250 | /*if (speedys.at(i)/speedy_step + abs(del)/100 < del)
251 | cur.setY(cur.y()+speedys.at(i)/speedy_step+del/100);
252 | else
253 | cur.setY(cur.y()+del);*/
254 | }
255 | else if (del < 0) // 应当往上移动
256 | {
257 | speedys[i]--; // 向上的加速度/
258 | // speedys[i] -= sqrt(-del)/speedx/speedy_step+1;
259 | /*if (speedys.at(i)/speedy_step+abs(del)/50 < -del)
260 | cur.setY(cur.y()-speedys.at(i)/speedy_step+del/50);
261 | else
262 | cur.setY(cur.y()+del);*/
263 | }
264 | cur.setY(cur.y()+speedys.at(i)/speedy_step);
265 | // qDebug() << sqrt(abs(del))/speedx/speedy_step+1;
266 | }
267 | // qDebug() << aim_keys[3].y() << keys[3].y() << speedys[3];
268 |
269 | // 每次绘图,更新一次Y方向的整体偏移量
270 | if (offsety+offsety_direct > -_max_offsety && offsety+offsety_direct < _max_offsety)
271 | offsety += offsety_direct;
272 | else if (offsety <= -_max_offsety)
273 | offsety = -_max_offsety;
274 | else if (offsety >= _max_offsety)
275 | offsety = _max_offsety;
276 |
277 | // x轴方向的偏移
278 | for (int i = 0; i < keys.length(); i++)
279 | {
280 | keys[i].setX(keys[i].x()+speedx);
281 | aim_keys[i].setX(keys[i].x());
282 | }
283 | offsetx += speedx;
284 |
285 | // 判断需不需要把右边移动到左边去
286 | if (offsetx >= inter)
287 | {
288 | qint64 timestamp = getTimestamp();
289 | QPoint p1(keys[0].x()-inter*2, getRandomHeight());
290 | QPoint p2(keys[0].x()-inter, getRandomHeight());
291 | keys.insert(0, p2);
292 | keys.insert(0, p1);
293 | aim_keys.insert(0, QPoint(p2));
294 | aim_keys.insert(0, QPoint(p1));
295 | speedys.insert(0, speedys.at(speedys.length()-1));
296 | speedys.insert(0, speedys.at(speedys.length()-2));
297 | aim_updates_timestamp.insert(0, timestamp);
298 | aim_updates_timestamp.insert(0, timestamp);
299 |
300 | offsetx -= inter*2;
301 |
302 | if (keys.length() > count+2)
303 | {
304 | keys.removeLast();
305 | keys.removeLast();
306 | aim_keys.removeLast();
307 | aim_keys.removeLast();
308 | speedys.removeLast();
309 | speedys.removeLast();
310 | aim_updates_timestamp.removeLast();
311 | aim_updates_timestamp.removeLast();
312 | }
313 | }
314 |
315 | // 更新当前界面
316 | target->update();
317 |
318 | /*QString ans = "";
319 | for (int i = 5; i < 8; i++)
320 | ans += " (" + QString::number(keys.at(i).y()) + ","+QString::number(keys.at(i).y())+")"+QString::number(speedys.at(i));
321 | qDebug() << ans;*/
322 | }
323 |
324 | void BezierWaveBean::slotSetOffset()
325 | {
326 | if (!running)
327 | {
328 | offsety_direct = 1;
329 | return ;
330 | }
331 | // 每隔一段时间,稍微修改波浪的上下偏移位置
332 | if (getRandom(0,1))
333 | offsety_direct = 1;
334 | else
335 | offsety_direct = -1;
336 | }
337 |
--------------------------------------------------------------------------------
/bezierwavebean.h:
--------------------------------------------------------------------------------
1 | #ifndef BEZIERWAVEBEAN_H
2 | #define BEZIERWAVEBEAN_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | class BezierWaveBean : public QObject
15 | {
16 | Q_OBJECT
17 | public:
18 | BezierWaveBean(QWidget *parent);
19 |
20 | void start();
21 | void resume();
22 | void pause();
23 |
24 | void set_count(int x);
25 | void set_offsety(int x);
26 | void set_speedx(int x);
27 | void set_rect(QRect rect);
28 |
29 | QPainterPath getPainterPath(QPainter &painter);
30 |
31 | protected:
32 | int getRandomHeight();
33 | int getRandom(int min, int max);
34 | qint64 getTimestamp();
35 |
36 | signals:
37 |
38 | public slots:
39 | void slotUpdateAims();
40 | void slotMovePoints();
41 | void slotSetOffset();
42 |
43 | protected:
44 | QWidget* target;
45 | int _offsety; // 多层波浪y轴偏移
46 | int _max_offsety; // y轴上下偏移的最大值
47 | QRect _rect;
48 |
49 | QTimer* update_timer;
50 | QTimer* move_timer;
51 | QTimer* offset_timer;
52 | QTimer* pause_timer;
53 |
54 | bool running;
55 |
56 | int count;
57 | int inter;
58 | int appear_speedy;
59 |
60 | int speedy, offsety;
61 | int offsety_direct;
62 | int speedx, offsetx;
63 | QListspeedys;
64 | int speedy_step;
65 | QListaim_updates_timestamp;
66 |
67 | QListkeys;
68 | QListaim_keys;
69 |
70 | std::random_device rd;
71 | std::mt19937 mt;
72 | };
73 |
74 | #endif // BEZIERWAVEBEAN_H
75 |
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | QApplication a(argc, argv);
7 | MainWindow w;
8 | w.show();
9 |
10 | return a.exec();
11 | }
12 |
--------------------------------------------------------------------------------
/mainwindow.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include "ui_mainwindow.h"
3 |
4 | MainWindow::MainWindow(QWidget *parent) :
5 | QMainWindow(parent), ui(new Ui::MainWindow),
6 | bw1(nullptr), bw2(nullptr), bw3(nullptr), bw4(nullptr), mt(rd())
7 | {
8 | ui->setupUi(this);
9 |
10 | bw1 = new BezierWaveBean(this);
11 | // bw1->set_offsety(geometry().height()/20);
12 | bw1->set_speedx(getRandom(1,5));
13 | bw1->start();
14 |
15 | bw2 = new BezierWaveBean(this);
16 | // bw2->set_offsety(geometry().height()/10);
17 | bw2->set_speedx(getRandom(1,5));
18 | bw2->start();
19 |
20 | bw3 = new BezierWaveBean(this);
21 | // bw3->set_offsety(geometry().height()*3/20);
22 | bw3->set_speedx(getRandom(1,5));
23 | bw3->start();
24 |
25 | bw4 = new BezierWaveBean(this);
26 | // bw4->set_offsety(geometry().height()/5);
27 | bw4->set_speedx(getRandom(1,5));
28 | bw4->start();
29 | }
30 |
31 | MainWindow::~MainWindow()
32 | {
33 | delete ui;
34 | }
35 |
36 | void MainWindow::paintEvent(QPaintEvent *e)
37 | {
38 | QPainter painter(this);
39 | painter.setRenderHint(QPainter::Antialiasing, true);
40 |
41 | QPainterPath bezier;
42 |
43 | if (bw1 != nullptr)
44 | bezier = bw1->getPainterPath(painter);
45 | painter.fillPath(bezier, QColor(255, 0, 0, 50));
46 |
47 | if (bw2 != nullptr)
48 | bezier = bw2->getPainterPath(painter);
49 | painter.fillPath(bezier, QColor(255, 0, 0, 50));
50 |
51 | if (bw3 != nullptr)
52 | bezier = bw3->getPainterPath(painter);
53 | painter.fillPath(bezier, QColor(255, 0, 0, 50));
54 |
55 | if (bw4 != nullptr)
56 | bezier = bw4->getPainterPath(painter);
57 | painter.fillPath(bezier, QColor(255, 0, 0, 50));
58 |
59 | return QMainWindow::paintEvent(e);
60 | }
61 |
62 | void MainWindow::resizeEvent(QResizeEvent *e)
63 | {
64 | bw1->set_rect(geometry());
65 | bw2->set_rect(geometry());
66 | bw3->set_rect(geometry());
67 | bw4->set_rect(geometry());
68 | return QMainWindow::resizeEvent(e);
69 | }
70 |
71 | int MainWindow::getRandom(int min, int max)
72 | {
73 | #if defined (Q_OS_WIN) || defined(Q_OS_LINUX)
74 | return mt() % (max-min+1) + min;
75 | #elif defined(Q_OS_MAC)
76 |
77 | #else
78 | return rand() % (max-min+1) + min;
79 | #endif
80 | }
81 |
82 | void MainWindow::on_pushButton_clicked()
83 | {
84 | bw1->pause();
85 | bw2->pause();
86 | bw3->pause();
87 | bw4->pause();
88 | }
89 |
90 | void MainWindow::on_pushButton_2_clicked()
91 | {
92 | bw1->resume();
93 | bw2->resume();
94 | bw3->resume();
95 | bw4->resume();
96 | }
97 |
--------------------------------------------------------------------------------
/mainwindow.h:
--------------------------------------------------------------------------------
1 | #ifndef MAINWINDOW_H
2 | #define MAINWINDOW_H
3 |
4 | #include
5 | #include "bezierwavebean.h"
6 |
7 | namespace Ui {
8 | class MainWindow;
9 | }
10 |
11 | class MainWindow : public QMainWindow
12 | {
13 | Q_OBJECT
14 |
15 | public:
16 | explicit MainWindow(QWidget *parent = nullptr);
17 | ~MainWindow();
18 |
19 | protected:
20 | void paintEvent(QPaintEvent* e) override;
21 | void resizeEvent(QResizeEvent* e) override;
22 |
23 | int getRandom(int min, int max);
24 |
25 | private:
26 |
27 |
28 | public slots:
29 |
30 |
31 | private slots:
32 | void on_pushButton_clicked();
33 |
34 | void on_pushButton_2_clicked();
35 |
36 | private:
37 | Ui::MainWindow *ui;
38 |
39 | BezierWaveBean *bw1, *bw2, *bw3, *bw4;
40 |
41 | std::random_device rd;
42 | std::mt19937 mt;
43 | };
44 |
45 | #endif // MAINWINDOW_H
46 |
--------------------------------------------------------------------------------
/mainwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 300
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
18 |
19 |
20 | 40
21 | 10
22 | 75
23 | 23
24 |
25 |
26 |
27 | 暂停
28 |
29 |
30 |
31 |
32 |
33 | 130
34 | 10
35 | 75
36 | 23
37 |
38 |
39 |
40 | 继续
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/pictures/picture.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iwxyi/Bezier-Wave/0d1deb85dec839e09a7723d3535b862ec8badffe/pictures/picture.gif
--------------------------------------------------------------------------------