Cyrus-Beck算法的计算方法
运算步骤
- 表示出 P ( t ) = P 0 + t ⋅ D P(t) = P_0 + t \cdot D P(t)=P0+t⋅D,求解其中的 D = P 1 − P 0 D = P_1 - P_0 D=P1−P0
- 计算每一条边指向多边形内部的法向量 N i N_i Ni
- 对每一条边都进行分组, N i ⋅ D > 0 N_i \cdot D > 0 Ni⋅D>0为Enter ( P E P_E PE),反之 N i ⋅ D < 0 N_i \cdot D < 0 Ni⋅D<0则为Exit ( P L P_L PL)
- 根据 t = − N i ⋅ ( P 0 − A i ) N i ⋅ D t = -\frac{N_i \cdot (P_0 - A_i)}{N_i \cdot D} t=−Ni⋅DNi⋅(P0−Ai)对 t t t进行求解。
- 在 P E P_E PE中寻找最大值,若全为负数则设为0;在 P L P_L PL中寻找最小值,若全为大于1的数则设为1。
- 将求到的 t e x i t t_{exit} texit 和 t e n t e r t_{enter} tenter带入1中的式子得到裁剪的线段的起点和终点。
例题
- 裁剪窗口:凸五边形,顶点按逆时针顺序为 A ( 2 , 1 ) A(2,1) A(2,1)、 B ( 4 , 2 ) B(4,2) B(4,2)、 C ( 5 , 4 ) C(5,4) C(5,4)、 D ( 3 , 5 ) D(3,5) D(3,5)、 E ( 1 , 3 ) E(1,3) E(1,3)。
- 待裁剪线段: P 0 ( 0 , 2 ) → P 1 ( 6 , 4 ) P_0(0,2) \to P_1(6,4) P0(0,2)→P1(6,4)(从左下到右上)。
(1) 参数化线段
P ( t ) = P 0 + t ⋅ D , D = P 1 − P 0 = ( 6 , 4 ) − ( 0 , 2 ) = ( 6 , 2 ) P(t) = P_0 + t \cdot D, \\ D = P_1 - P_0 = (6, 4) - (0, 2) = (6, 2) P(t)=P0+t⋅D,D=P1−P0=(6,4)−(0,2)=(6,2)
其中 t ∈ [ 0 , 1 ] t\in[0,1] t∈[0,1]。
(2) 五边形各边的法向量(内法向)
对每条边 E i E_i Ei,计算内法向量 N i = ( E i y , − E i x ) N_i=(E_{iy},-E_{ix}) Ni=(Eiy,−Eix)(垂直于边并指向内部):
- 边 A B AB AB:向量 B − A = ( 2 , 1 ) B-A=(2,1) B−A=(2,1),法向量 N 1 = ( − 1 , 2 ) N_1=(-1,2) N1=(−1,2)。
- 边 B C BC BC:向量 C − B = ( 1 , 2 ) C-B=(1,2) C−B=(1,2),法向量 N 2 = ( − 2 , 1 ) N_2=(-2,1) N2=(−2,1)。
- 边 C D CD CD:向量 D − C = ( − 2 , 1 ) D-C=(-2,1) D−C=(−2,1),法向量 N 3 = ( − 1 , − 2 ) N_3=(-1,-2) N3=(−1,−2)。
- 边 D E DE DE:向量 E − D = ( − 2 , − 2 ) E-D=(-2,-2) E−D=(−2,−2),法向量 N 4 = ( 2 , − 2 ) N_4=(2,-2) N4=(2,−2)。
- 边 E A EA EA:向量 A − E = ( 1 , − 2 ) A-E=(1,-2) A−E=(1,−2),法向量 N 5 = ( 2 , 1 ) N_5=(2,1) N5=(2,1)。
(3) 计算每条边的交点参数 t t t
对每条边 E i E_i Ei,计算:
t = − N i ⋅ ( P 0 − A i ) N i ⋅ D 或 t = N i ⋅ ( A i − P 0 ) N i ⋅ D t = -\frac{N_i \cdot (P_0 - A_i)}{N_i \cdot D} \\ 或 \quad t = \frac{N_i \cdot (A_i - P_0)}{N_i \cdot D} \\ t=−Ni⋅DNi⋅(P0−Ai)或t=Ni⋅DNi⋅(Ai−P0)
注意: A i A_i Ai 为每条边的起点。
并分类为PE(进入)或PL(离开)。
边 | 法向量 N i N_i Ni | N i ⋅ D N_i \cdot D Ni⋅D | W = P 0 − A i W=P_0-A_i W=P0−Ai | N i ⋅ W N_i \cdot W Ni⋅W | t t t | 分类 |
---|---|---|---|---|---|---|
AB | ( − 1 , 2 ) (-1,2) (−1,2) | − 1 ⋅ 6 + 2 ⋅ 2 = − 2 -1 \cdot 6 + 2 \cdot 2 = -2 −1⋅6+2⋅2=−2 | ( 0 − 2 , 2 − 1 ) = ( − 2 , 1 ) (0-2,2-1)=(-2,1) (0−2,2−1)=(−2,1) | − 1 ⋅ ( − 2 ) + 2 ⋅ 1 = 4 -1 \cdot (-2) + 2 \cdot 1 = 4 −1⋅(−2)+2⋅1=4 | t = 2 t=2 t=2 | PL |
BC | ( − 2 , 1 ) (-2,1) (−2,1) | − 2 ⋅ 6 + 1 ⋅ 2 = − 10 -2 \cdot 6 + 1 \cdot 2 = -10 −2⋅6+1⋅2=−10 | ( 0 − 4 , 2 − 2 ) = ( − 4 , 0 ) (0-4,2-2)=(-4,0) (0−4,2−2)=(−4,0) | − 2 ⋅ ( − 4 ) + 1 ⋅ 0 = 8 -2 \cdot (-4) + 1 \cdot 0 = 8 −2⋅(−4)+1⋅0=8 | t = 0.8 t=0.8 t=0.8 | PL |
CD | ( − 1 , − 2 ) (-1,-2) (−1,−2) | − 1 ⋅ 6 + ( − 2 ) ⋅ 2 = − 10 -1 \cdot 6 + (-2) \cdot 2 = -10 −1⋅6+(−2)⋅2=−10 | ( 0 − 5 , 2 − 4 ) = ( − 5 , − 2 ) (0-5,2-4)=(-5,-2) (0−5,2−4)=(−5,−2) | − 1 ⋅ ( − 5 ) + ( − 2 ) ⋅ ( − 2 ) = 9 -1 \cdot (-5) + (-2) \cdot (-2) = 9 −1⋅(−5)+(−2)⋅(−2)=9 | t = 0.9 t=0.9 t=0.9 | PL |
DE | ( 2 , − 2 ) (2,-2) (2,−2) | 2 ⋅ 6 + ( − 2 ) ⋅ 2 = − 8 2 \cdot 6 + (-2) \cdot 2 = -8 2⋅6+(−2)⋅2=−8 | ( 0 − 3 , 2 − 5 ) = ( − 3 , − 3 ) (0-3,2-5)=(-3,-3) (0−3,2−5)=(−3,−3) | 2 ⋅ ( − 3 ) + ( − 2 ) ⋅ ( − 3 ) = 0 2 \cdot (-3) + (-2) \cdot (-3) = 0 2⋅(−3)+(−2)⋅(−3)=0 | t = 0 t=0 t=0 | PE |
EA | ( 2 , 1 ) (2,1) (2,1) | 2 ⋅ 6 + 1 ⋅ 2 = 14 2 \cdot 6 + 1 \cdot 2 = 14 2⋅6+1⋅2=14 | ( 0 − 1 , 2 − 3 ) = ( − 1 , − 1 ) (0-1,2-3)=(-1,-1) (0−1,2−3)=(−1,−1) | 2 ⋅ ( − 1 ) + 1 ⋅ ( − 1 ) = − 3 2 \cdot (-1) + 1 \cdot (-1) = -3 2⋅(−1)+1⋅(−1)=−3 | t = 3 14 ≈ 0.214 t = \frac{3}{14} \approx 0.214 t=143≈0.214 | PE |
(4) 分类并确定 t enter t_{\text{enter}} tenter和 t exit t_{\text{exit}} texit
- PE组(进入): t = 0 t=0 t=0(DE边)、 t ≈ 0.214 t\approx0.214 t≈0.214(EA边)。
t enter = max ( 0 , 0.214 ) = 0.214 t_{\text{enter}}=\max(0,0.214)=0.214 tenter=max(0,0.214)=0.214。 - PL组(离开): t = 0.8 t=0.8 t=0.8(BC边)、 t = 0.9 t=0.9 t=0.9(CD边)、 t = 2 t=2 t=2(AB边)。
t exit = min ( 0.8 , 0.9 , 2 ) = 0.8 t_{\text{exit}}=\min(0.8,0.9,2)=0.8 texit=min(0.8,0.9,2)=0.8。
(5) 裁剪结果
- 因为 t enter = 0.214 ≤ t exit = 0.8 t_{\text{enter}}=0.214 \leq t_{\text{exit}}=0.8 tenter=0.214≤texit=0.8,线段部分可见。
- 可见部分:
P ( 0.214 ) = ( 0 + 0.214 × 6 , 2 + 0.214 × 2 ) ≈ ( 1.28 , 2.43 ) P(0.214)=(0+0.214 \times 6, 2+0.214\times2)\approx(1.28,2.43) P(0.214)=(0+0.214×6,2+0.214×2)≈(1.28,2.43)。
P ( 0.8 ) = ( 0 + 0.8 × 6 , 2 + 0.8 × 2 ) = ( 4.8 , 3.6 ) P(0.8)=(0+0.8 \times 6, 2+0.8\times2)=(4.8,3.6) P(0.8)=(0+0.8×6,2+0.8×2)=(4.8,3.6)。 - 裁剪后线段: ( 1.28 , 2.43 ) → ( 4.8 , 3.6 ) (1.28,2.43)\to(4.8,3.6) (1.28,2.43)→(4.8,3.6)。