裁剪是3D图形的一个非常重要的方面,二维裁剪功能被广泛的应用于三维图像领域。本文结合Java代码实例,介绍一个非常好,但又足够简单的裁剪算法-科恩-萨瑟兰算法.
在绘制2D线段时,线段的一个端点或者两个端点可能位于屏幕外面,而其中的一部分仍然是可见的。在这种情况下,需要一个有效的算法来查找可见部分的两个新端点,只绘制基于新端点的线段,所有在屏幕外的部分被裁剪掉,从而提高程序的效率。
算法
绘制线段时,如果线段的一个端点是屏幕外,另一个在里面,通过裁剪,只保留屏幕内部的部分。即使两个端点都在画面外,该线段的一部分也可能是可见的。裁剪算法需要找到可见部分线段的新端点,新端点位于屏幕内部或屏幕的边缘。如下图,黑色矩形表示屏幕,红色是原始线段的端点,蓝色为裁剪后线段的端点:
- A:两个端点都在屏幕上,无需裁剪。
- B:一个端点在屏幕外,一个端点在屏幕内部,屏幕外的端点需要被裁剪。
- C:两个端点都在屏幕外面,该线段的任何部分都不可见,无需裁剪
- D:两个端点是画面外,但线段的一部分是可见的,两个端点都需要被裁剪。
如果继续细分,还有很多不同的情况,比如,每个端点可以在屏幕内部,左边,右边,上面,下面,等… 本算法可以非常有效地识别这些情况,并作对应的裁剪。
该算法将2D空间分为9个区域:中心区域是在屏幕,其它的8个区域是在屏幕以外的不同侧面。每个区域用一个四位的二进制数来标识,该二进制数标识被称为区域码(“outcode”)。编码如下:
- 如果该区域在屏幕的上方,第一个字节位是1
- 如果该区域在屏幕的下方,第二个字节位是1
- 如果该区域在屏幕的右边,第三个字节位是1
- 如果该区域在屏幕的左侧,第四个字节位为1
显然,同一区域不能同时在左和右边,或同时在上方和下方,所以在第三字节位和第四字节位不能为同时为1,第一字节位和第二字节位的不能同时为1。屏幕区域的4个字节位全部为0。
屏幕区域的Java定义如下,
private static final int INSIDE = 0;
private static final int LEFT = 1;
private static final int RIGHT = 2;
private static final int BOTTOM = 4;
private static final int TOP = 8;
线段的两个端点可以位于任意9个区域,我们先从一些简单的情形入手:
- 如果两个端点均在屏幕的内部或边缘,该线段不需要裁剪并需要全部绘制。这种情况下,是简单接受(Trivial Accept)。
- 如果两个端点均在屏幕(例如,两个端点都在屏幕上方)的同一侧,线段的任何部分都不在屏幕上,该线段不需要裁剪并不需绘制,这种情况下,是简单拒绝(Trivial Reject&#