Linear Interpolation 是我阅读问题时的第一个想法(以及the other answer 中提到的)。
插值的一般公式是:
x = (1 - t) · x0 + t · x1
x ...插值
x0 ... 起始值
x1 ...目标值
t ... [0, 1] 范围内的插值参数
当我意识到一些可能形成可能限制的事实(不幸的是,OP 没有明确提及)时,我什至打算写这个作为答案。
- 所有操作都是关于整数值。因此,可能首选进行整数运算。
-
mouse_event() 和 AccurateSleep() 使用 delta 值调用。这可能由 OP 使用的 API 决定。
所以,我三思而后行,并提出了以下MCVE 类似于 OPs 问题:
#include <iostream>
static int xMouse = 0, yMouse = 0, t = 0;
void mouse_event(int _1, int dx, int dy, int _4, int _5)
{
xMouse += dx; yMouse += dy;
std::cout << "mouse_event(" << _1 << ", " << dx << ", " << dy << ", " << _4 << ", " << _5 << "): "
<< xMouse << ", " << yMouse << '\n';
}
void AccurateSleep(int delay)
{
t += delay;
std::cout << "AccurateSleep(" << delay << "): " << t << '\n';
}
void Sleep(int delay)
{
t += delay;
std::cout << "Sleep(" << delay << "): " << t << '\n';
}
void Smoothing(int smoothing, int delay, int x, int y)
{
for (int i = 0; i < smoothing; i++) {
mouse_event(1, x / smoothing, y / smoothing, 0, 0);
AccurateSleep(delay / smoothing);
}
mouse_event(1, x % smoothing, y % smoothing, 0, 0);
Sleep(delay % smoothing);
}
#define PRINT_AND_DO(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
PRINT_AND_DO(xMouse = 0; yMouse = 0; t = 0);
PRINT_AND_DO(Smoothing(10, 132, 14, 30));
PRINT_AND_DO(xMouse = 0; yMouse = 0; t = 0);
PRINT_AND_DO(Smoothing(20, 15, 10, 0));
}
输出:
xMouse = 0; yMouse = 0; t = 0;
Smoothing(10, 132, 14, 30);
mouse_event(1, 1, 3, 0, 0): 1, 3
AccurateSleep(13): 13
mouse_event(1, 1, 3, 0, 0): 2, 6
AccurateSleep(13): 26
mouse_event(1, 1, 3, 0, 0): 3, 9
AccurateSleep(13): 39
mouse_event(1, 1, 3, 0, 0): 4, 12
AccurateSleep(13): 52
mouse_event(1, 1, 3, 0, 0): 5, 15
AccurateSleep(13): 65
mouse_event(1, 1, 3, 0, 0): 6, 18
AccurateSleep(13): 78
mouse_event(1, 1, 3, 0, 0): 7, 21
AccurateSleep(13): 91
mouse_event(1, 1, 3, 0, 0): 8, 24
AccurateSleep(13): 104
mouse_event(1, 1, 3, 0, 0): 9, 27
AccurateSleep(13): 117
mouse_event(1, 1, 3, 0, 0): 10, 30
AccurateSleep(13): 130
mouse_event(1, 4, 0, 0, 0): 14, 30
Sleep(2): 132
xMouse = 0; yMouse = 0; t = 0;
Smoothing(20, 15, 10, 0);
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 10, 0, 0, 0): 10, 0
Sleep(15): 15
然后我修改Smoothing()实现上面提到的插值公式,并针对具体情况做了一些调整:
- 对于t,使用
i / smoothing(i 在 [1,平滑] 范围内)。
- 虽然循环对每个
i 进行插值,但前一次迭代的值被保留并用于计算 mouse_event() 和 AccurateSleep() 的函数调用的增量值。
- 当然,运算顺序很重要,因为这是整数运算。因此,
xI = i * x / smoothing 不等于 xI = i / smoothing * x。 (即这些积分运算不提供交换性。)
修改后的Smoothing():
void Smoothing(int smoothing, int delay, int x, int y)
{
int x_ = 0, y_ = 0, t_ = 0;
for (int i = 1; i <= smoothing; ++i) {
// i / smoothing provides the interpolation paramter in [0, 1]
int xI = i * x / smoothing;
int yI = i * y / smoothing;
int tI = i * delay / smoothing;
mouse_event(1, xI - x_, yI - y_, 0, 0);
AccurateSleep(tI - t_);
x_ = xI; y_ = yI; t_ = tI;
}
}
输出:
xMouse = 0; yMouse = 0; t = 0;
Smoothing(10, 132, 14, 30);
mouse_event(1, 1, 3, 0, 0): 1, 3
AccurateSleep(13): 13
mouse_event(1, 1, 3, 0, 0): 2, 6
AccurateSleep(13): 26
mouse_event(1, 2, 3, 0, 0): 4, 9
AccurateSleep(13): 39
mouse_event(1, 1, 3, 0, 0): 5, 12
AccurateSleep(13): 52
mouse_event(1, 2, 3, 0, 0): 7, 15
AccurateSleep(14): 66
mouse_event(1, 1, 3, 0, 0): 8, 18
AccurateSleep(13): 79
mouse_event(1, 1, 3, 0, 0): 9, 21
AccurateSleep(13): 92
mouse_event(1, 2, 3, 0, 0): 11, 24
AccurateSleep(13): 105
mouse_event(1, 1, 3, 0, 0): 12, 27
AccurateSleep(13): 118
mouse_event(1, 2, 3, 0, 0): 14, 30
AccurateSleep(14): 132
xMouse = 0; yMouse = 0; t = 0;
Smoothing(20, 15, 10, 0);
mouse_event(1, 0, 0, 0, 0): 0, 0
AccurateSleep(0): 0
mouse_event(1, 1, 0, 0, 0): 1, 0
AccurateSleep(1): 1
mouse_event(1, 0, 0, 0, 0): 1, 0
AccurateSleep(1): 2
mouse_event(1, 1, 0, 0, 0): 2, 0
AccurateSleep(1): 3
mouse_event(1, 0, 0, 0, 0): 2, 0
AccurateSleep(0): 3
mouse_event(1, 1, 0, 0, 0): 3, 0
AccurateSleep(1): 4
mouse_event(1, 0, 0, 0, 0): 3, 0
AccurateSleep(1): 5
mouse_event(1, 1, 0, 0, 0): 4, 0
AccurateSleep(1): 6
mouse_event(1, 0, 0, 0, 0): 4, 0
AccurateSleep(0): 6
mouse_event(1, 1, 0, 0, 0): 5, 0
AccurateSleep(1): 7
mouse_event(1, 0, 0, 0, 0): 5, 0
AccurateSleep(1): 8
mouse_event(1, 1, 0, 0, 0): 6, 0
AccurateSleep(1): 9
mouse_event(1, 0, 0, 0, 0): 6, 0
AccurateSleep(0): 9
mouse_event(1, 1, 0, 0, 0): 7, 0
AccurateSleep(1): 10
mouse_event(1, 0, 0, 0, 0): 7, 0
AccurateSleep(1): 11
mouse_event(1, 1, 0, 0, 0): 8, 0
AccurateSleep(1): 12
mouse_event(1, 0, 0, 0, 0): 8, 0
AccurateSleep(0): 12
mouse_event(1, 1, 0, 0, 0): 9, 0
AccurateSleep(1): 13
mouse_event(1, 0, 0, 0, 0): 9, 0
AccurateSleep(1): 14
mouse_event(1, 1, 0, 0, 0): 10, 0
AccurateSleep(1): 15
Live Demo on coliru
注意:
最后一次迭代是用i == smoothing 完成的,所以i / smoothing 的结果是 1。因此,最后一个插值步骤会产生精确的值——不需要像 OP 原始方法那样进行后校正。