计算机图形学:多边形填充算法(算法原理及代码实现)

一、实现方案

扫描线算法:

实现原理:

       把图形的填充转换为扫描线从上往下扫描填充,这时我们只需要判断每一条扫描线与图形的交点,而我们可以根据扫描线的连贯性,对交点进行排序,第1个点与第2个点之间,第3个点与第4个点之间.....
       依照此原理可以对图形进行扫描线算法扫描转换多边形,其中在判断上述交点时,还会出现扫描线与边重合、扫描线与边的交点为顶点等现象,具体实现步骤如下。

实现步骤:

1、找到多边形的最大Ymax和最小Ymin,在此范围内扫描多边形逐条;

2、一条扫描线y,求与多边形的交点(通过与每一条边的求交,步骤如下),首先定义一个交点表
     (1)如果该边是水平的,并且边的Y值=y,直接将该线画出来
     (2)如果该边与y无交点,跳过
     (3)该边与y有交点,求出交点(qx,qy)
            i.如果该点是顶点

             ①如果该点极值点,将该点x加入表两次

             ①否则将该x加入表一次<通过判断顶点相交的两点是否在一侧>

            Ii.如果不是顶点,则直接将该x加入表中

     (4)对交点的x进行排序
     (5)按照扫描线的连贯性进行填充
     (6)重复上述操作

注:设计多边形时,需要按顺序导入点

种子填充算法

实现原理:

       通过区域的4连通和8连通(区域内每一个像素可以通过四个方向(上、下、左、右)组合到达。),从四个方向寻找下一像素者来完成整个区域的填充。

实现步骤:

  1. 设(x,y)为内点表示的4连通区域内的一点,oldColor为区域的原色,newColor为填充后的颜色。
  2. 确定多边形的边界,并初始化区域内部原色
  3. 以(x,y)开始,每次向(上、下、左、右)四个点延伸,判断该点颜色,如果为newColor,递归终止。否则填充该点颜色为newColor,并以该点开始递归开始步骤3
  4. 所有点都被点亮,递归终止

注:实现代码只能完成矩形的填充

二、代码实现

任务A(扫描线算法填充): 

实现代码:

源代码:

class  MyPolygon
{
public:
    int m_VerticeNumber;
    CPoint m_Vertex[50];
    COLORREF m_LineColor;
};

//--------------------------------
int getMiny(MyPolygon ThePolygon)
{
    int min = ThePolygon.m_Vertex[0].y;
    for (int i = 1; i < ThePolygon.m_VerticeNumber; i++)
        if (min > ThePolygon.m_Vertex[i].y)
            min = ThePolygon.m_Vertex[i].y;
    return min;
}

int getMaxy(MyPolygon ThePolygon)
{
    int max = ThePolygon.m_Vertex[0].y;
    for (int i = 1; i < ThePolygon.m_VerticeNumber; i++)
        if (max < ThePolygon.m_Vertex[i].y)
            max = ThePolygon.m_Vertex[i].y;
    return max;
}

//交换
void Swap(int* a, int i, int j) {
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}
//随机快速排序

int qsort(int* a, int begin, int end) {
    int i, j, temp;
    i = begin - 1; j = begin;
    for (; j < end; j++)
    {
        if (a[j] <= a[end - 1])
            Swap(a, ++i, j);
    }
    return i;
}

void randqsort(int* a, int begin, int n) {
    while (begin >= n)
        return;
    srand((unsigned)time(NULL));
    int key = (begin + rand() % (n - begin));
    Swap(a, key, n - 1);
    int m = qsort(a, begin, n);
    randqsort(a, begin, m);
    randqsort(a, m + 1, n);
}

void ScanFill(CDC* pDC, MyPolygon ThePolygon, CPoint startPoint, COLORREF fillCol)
{
    int miny, maxy;
    int sx, sy, tx, ty;
    miny = getMiny(ThePolygon);
    maxy = getMaxy(ThePolygon);
    int* index = new int[100];
    int* judge = new int[ThePolygon.m_VerticeNumber];
    memset(index, -1, sizeof(int) * 100);
    memset(judge, 0, sizeof(int) * ThePolygon.m_VerticeNumber);
    int x;
    CPoint Point;
    for (int i = miny; i <= maxy; i++)
    {
        //记录扫描线与边线的交点
        int temp = 0;
        for (int i1 = 0, L = ThePolygon.m_VerticeNumber, j1 = L - 1; i1 < L; j1 = i1, i1++) {

            sx = ThePolygon.m_Vertex[i1].x;
            sy = ThePolygon.m_Vertex[i1].y;
            tx = ThePolygon.m_Vertex[j1].x;
            ty = ThePolygon.m_Vertex[j1].y;
            int lowy, heighty;
            lowy = (sy < ty) ? sy : ty;
            heighty = (sy > ty) ? sy : ty;
            //水平线
            if (ty == sy)
            {
                if (i == ty)
                {
                    int xmax, xmin;
                    xmax = (sx > tx) ? sx : tx;
                    xmin = (sx < tx) ? sx : tx;
                    for (int xx = xmin; xx <= xmax; xx++)
                    {
                        Point.x = xx; Point.y = i;
                        pDC->SetPixelV(Point, fillCol);
                    }
                }
                continue;
            }
            //没有交点
            if (i<lowy || i>heighty)
                continue;
            x = sx + (i - sy) * (tx - sx) / (ty - sy);
            //判断交点(x,i)是不是顶点
            if ((x == ThePolygon.m_Vertex[i1].x && i == ThePolygon.m_Vertex[i1].y))
            {
                //判断顶点是不是极值点  
                //即判断与交点相关联的两条线的另外两个顶点是不是在交点的同一侧
                if (i1 != L - 1 && judge[i1] == 0) {
                    if ((i - ThePolygon.m_Vertex[i1 + 1].y) * (i - ThePolygon.m_Vertex[j1].y) < 0)//异号
                        index[temp++] = x;
                    else//同号  极值点 记录两次
                    {
                        index[temp++] = x;
                        index[temp++] = x;
                    }
                }
                else if (i1 == L - 1 && judge[i1] == 0)
                {
                    if ((i - ThePolygon.m_Vertex[0].y) * (i - ThePolygon.m_Vertex[j1].y) < 0) {//异号
                        index[temp++] = x;
                    }
                    else//同号  极值点  记录两次
                    {
                        index[temp++] = x;
                        index[temp++] = x;
                    }
                }
                judge[i1] = 1;
                continue;
            }
            else if ((x == ThePolygon.m_Vertex[j1].x && i == ThePolygon.m_Vertex[j1].y))
            {
                if (j1 != 0 && judge[j1] == 0) {
                    if ((i - ThePolygon.m_Vertex[i1].y) * (i - ThePolygon.m_Vertex[j1 - 1].y) < 0) {//异号
                        index[temp++] = x;

                    }
                    else//同号  极值点
                    {
                        index[temp++] = x;
                        index[temp++] = x;
                    }

                }
                else if (j1 == 0 && judge[j1] == 0)
                {
                    if ((i - ThePolygon.m_Vertex[i1].y) * (i - ThePolygon.m_Vertex[l - 1].y) < 0)//异号
                        index[temp++] = x;
                    else//同号  极值点
                    {
                        index[temp++] = x;
                        index[temp++] = x;
                    }
                }
                judge[j1] = 1;
                continue;
            }
            //交点不是顶点
            index[temp++] = x;
        }

        //将index排序
        randqsort(index, 0, temp);//随机快速

        //填充多边形
        for (int n = 0, m = n + 1; m < temp && index[n] != -1; n += 2, m = n + 1)
        {
            for (int xx = index[n]; xx <= index[m]; xx++)
            {
                Point.x = xx; Point.y = i;
                pDC->SetPixelV(Point, fillCol);
            }
        }
        //清零
        for (int k = 0; k < 100; k++)
            index[k] = -1;
    }
    delete[] index;
    delete[] judge;
}

任务B(种子填充算法):

实现代码:

 源代码:

void FloodFill4(CDC* pDC, int x, int y, int Color) {
    
    if((x<20 )&& (x>-20)&& (y > -20) && (y < 20)&&(pDC->GetPixel(x ,y) != Color)){
        pDC->SetPixel(x, y, Color);
        FloodFill4(pDC, x, y - 1,Color);
        FloodFill4(pDC, x + 1, y,Color);
        FloodFill4(pDC, x - 1, y,Color);
        FloodFill4(pDC, x, y + 1,Color);
    }
    else{
        return;
    }
}

三、算法结果

任务A:

任务B:

  • 8
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值