theme: cyanosis
0. 问题描述:
最近在研究一个功能,期间演化出一些比较有趣的小知识。我把它们整理成独立的问题,来分享给大家。首先来解释一下,什么叫 一维区域空间的中心缩放:
比如,现在有一个刻度尺,视口区域是 [4,12]
,现在求:
若以 8 为缩放中心,将尺子放大两倍。求前视口的刻度区域。
缩放中心,就是在缩放变换过程中的不动点。我们可以把尺子放大两倍后,将区域对应的缩放中心和 8 对齐。下面可以从图中看出,当前视口区域的在 [6,10]
:
于是,就可以抛出本文研究的目标:
一维空间中的 [a,b] 区域,以 c 点为缩放中心,缩放 s 倍,求区域此的范围。
1. 解决思路
现在先分析一下上面案例中的细节,从数学的角度上理解一下,为什么结果是 [6,10]
[4,12]
以 8 为中心放大两倍。
- 原区域刻度长度: 12 - 4 = 8
- 当刻度尺放大两倍,而视口区域不变。则视口刻度长度将会减半。
- 缩放中心的刻度保持不变。
根据上面三点特征,我们就可以将模型简化为,求解区域前后刻度的问题。如下所示,两个问号分别是多少:
小学毕业了的朋友应该可以很轻松地报出答案:
左侧: 8 - 4/2 = 6
右侧: 8 + 4/2 = 10
我们真的将尺子放大两倍,然后观测效果,对规律进行总结,这是 物理学。而对于 数学 来说,根据已知条件,通过逻辑进行推演,就能得到答案。
2. 缩放执行非中点
如下所示,如果此时将缩放中心设置为 10 ,通过真实的缩放观察可以看出结果是 [7~11]。此时缩放中心左侧空间的占比是 (10-4)/(12-4)
。尺子放大之后,区域总刻度是 4 ,则左侧空间程度 (12-4)/2 * (10-4)/(12-4) = 3
。
于是缩放后左侧刻度 10-3 = 7
,右侧自然也就是 10+(4-3) = 11
3. 一般化的一维空间中心缩放
现在我们可以根据推演的逻辑,将这个规律适用于一般化的场合
一维空间中的 [a,b] 区域,以 c 点为缩放中心,缩放 s 倍,求区域此的范围。
- 原区域刻度长度: b - a
- 当刻度尺放大 s 倍,而视口区域不变。则视口刻度长度将缩小 s 倍。
- 缩放中心的刻度保持不变。
左侧坐标: c - (b-a)/s * [(c-a)/(b-a)]
右侧坐标: c + (b-a)/s * [(b-c)/(b-a)]
4. 演算的编程实现
如下所示,定义一个 Area
类型标识区间左右刻度;scale
方法将用于对 Area 对象以 c 为中心,缩放 s 倍:
```dart void main() { Area area = Area(4, 12); double center = 10; double s = 2;
Area ret = scale(area, center, s); print(ret); }
Area scale(Area area, double c, double s) { double len = area.b - area.a; double lenL = c - area.a; double lenR = area.b - c; return Area( c - len / s * (lenL / len), c + len / s * (lenR / len), ); }
class Area { final double a; final double b;
Area(this.a, this.b);
@override String toString() { return 'Area[$a ~ $b]'; } } ```
可能会有人问,这有什么用? 下一篇,将向你展示这个小方法的强大威力。敬请期待 ~