更新回调
点的更新回调
使用回调机制,允许设置回调函数:
void Point2D::on_update(const std::function<void(const double &, const double &, const double &, const double &)> callback) {
_callback = callback;
}
void Point2D::on_update() {
_callback = [](const double &lx, const double &ly, const double &x, const double &y){};
}
每次进行更新时,检查与当前值的差是否大于 1 e − 6 1e^{-6} 1e−6,否则认为未被更新;然后调用回调函数:
if (!(_eq(_x, last_x) && _eq(_y, last_y))) _callback(last_x, last_y, _x, _y);
基于回调传播图像更新
主动点 & 从动点
关键点的移动,引发了一个几何学的主从动点问题。主从动点的概念来源于一次更新。
- 主动点:在一次更新中不受其他点的约束而位置发生改变。
- 从动点:再一次更新受其他点的约束而位置发生改变。
在图形绘制中,用户移动的点一定是主动点,此时被引发变化的点一定是从动点。
将主从动点的关系扩展到多次更新,那么主从动点的关系在每次更新中都有体现。在前一次更新中作为从动点的点,成为下一次更新的主动点;如此循环往复,形成了多条更新链;按照更新的次数划分层数,令主动点指向从动点,可以得到一个有向无环图;如果使用状态机模型,则可能存在环。
称上述过程为更新传播。
注意:更新的前提是位置发生改变,如果约束并没有使某点发生改变,则该点并不是从动点。
合法更新域
并不是所有更新位置都是合法的。例如矩形的顶边中点:
它的合法更新域为
x
x
x于其相等的直线。但是更本质的描述是,它必须是左上于右上点连接成的线段点中点。
每次更新传播中的约束,应当保证从动点移动到它的合法更新域。若不合法,则应当回溯。
另外,在首次更新前,可以通过认为限制,例如对用户的输入进行预处理,从而保证首次更新中的主动点在合法更新域中。
基于回调传播更新
矩形更新例子
-
回调函数
分为两个部分。
-
四个顶点
在回调函数中首先更新相邻的顶点,再由相邻的顶点计算邻边的中点。以左上角顶点LT为例:
LB->setX(nx); RT->setY(ny); *L = (*LT + *LB) * 0.5; *T = (*LT + *RT) * 0.5;
-
四个边的中点
在回调函数中直接更新相邻的顶点。以顶边中点为例:
LT->setY(ny), RT->setY(ny);
-
-
更新过程模拟
假设对LT作更新,则经过如下更新传播过程后得到结果:
-
收敛性
只要约束是稳定关系,就能保证收敛。
-
非收敛情形
如果是非稳定关系,可以通过引入迭代次数,限制迭代次数从而强制收敛;对于迭代中在稳定状态附近震荡的情形,可以引入精度,当当前状态满足一定精度时停止。