扫描线填充算法(2)

原创 2016年08月30日 10:55:15

扫描线填充算法(2)
活动边表示扫描线填充算法的核心,整个算法都是围绕着这张表进行处理的。要完整的定义“活动边表”,需要定义边的数据结构。每条边都和扫描线有个交点,扫描线填充算法只关注交点的x坐标。每当处理下一条扫描线时,根据xi+1/m直接计算出扫描线与边的交点x坐标,可以避免复杂的求交计算。一条边不会一直待在“活动边表”中,当扫描线与之没有交点时,要将其从“活动边表”中删除,判断是否有交点的依据就是看扫描线y是否大于这条边两个端点的y坐标值,为此,需要记录边的y坐标的最大值。

// FillPolygon.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <cstdio>
#include <malloc.h>
#include <cmath>
#include <vector>
#include <GL/glut.h>
#include <iostream>
#include <list>
using namespace std;

#pragma comment(linker,"/entry:\"mainCRTStartup\"")
#define MAX_VERTECES 100
#define WINDOWWIDTH 400
#define WINDOWHEIGHT 400
#define ACCURACY 0.1
#define max(x,y) (x)>(y)?(x):(y)
#define min(x,y) (x)<(y)?(x):(y)
#define drawLine(x1,y1,x2,y2) glBegin(GL_LINES);glVertex2i((x1),(y1));glVertex2i((x2),(y2));glEnd();

typedef struct Edge{
    int ymax;
    float xi, dx;
}Edge;

typedef struct Point{
    GLint x, y;
}Point;

typedef struct Polygon{
    Point pts[MAX_VERTECES];
    int polycnt;
}Polygon;

int ymin, ymax;

GLint verteces[MAX_VERTECES][2];
GLint pointn = 0;
GLint windowwidth = WINDOWWIDTH, windowheight = WINDOWHEIGHT;
GLint finish_picking_points = GL_FALSE;
GLint begin_to_draw = GL_FALSE;

list<Edge> slNet[WINDOWHEIGHT];
list<Edge> aet;

Polygon py;

void newPloygon()
{
    py.polycnt = pointn;
    ymin = 10000000;
    ymax = 0;
    for (int i = 0; i < pointn; i++)
    {
        py.pts[i].x = verteces[i][0];
        py.pts[i].y = verteces[i][1];
        ymin = min(ymin, verteces[i][1]);
        ymax = max(ymax, verteces[i][1]);
    }
}

void initScanLineNewEdgeTable()
{
    for (int i = 0; i < WINDOWHEIGHT; i++)
    {
        slNet[i].clear();
    }
    Edge e;

    for (int i = 0; i < py.polycnt; i++)
    {
        const Point & ps = py.pts[i];
        const Point & pe = py.pts[(i + 1) % py.polycnt];
        const Point & pee = py.pts[(i + 2) % py.polycnt];
        const Point & pss = py.pts[(i - 1 + py.polycnt) % py.polycnt];

        if (pe.y != ps.y)
        {
            e.dx = (double)(pe.x - ps.x) / (double)(pe.y - ps.y);
            if (pe.y > ps.y)
            {
                e.xi = ps.x;
                if (pee.y >= pe.y)
                {
                    e.ymax = pe.y - 1;
                }
                else
                {
                    e.ymax = pe.y;
                }
                slNet[ps.y].push_front(e);
            }
            else
            {
                e.xi = pe.x;
                if (pss.y >= ps.y)
                {
                    e.ymax = ps.y - 1;
                }
                else
                {
                    e.ymax = ps.y;
                }
                slNet[pe.y].push_front(e);
            }
        }
    }
}

void HorizonEdgeFill()
{
    int id1, id2;
    int x1, x2, y1, y2;
    for (int i = 0; i < py.polycnt; i++)
    {
        id1 = i;
        id2 = (i + 1) % py.polycnt;
        if (py.pts[id1].y == py.pts[id2].y)
        {
            x1 = py.pts[id1].x;
            y1 = py.pts[id1].y;
            x2 = py.pts[id2].x;
            y2 = py.pts[id2].y;
            drawLine(x1, y1, x2, y2);
        }
    }
    glFlush();
}
bool EdgeXiComparator(Edge& e1, Edge& e2)
{
    return e1.xi < e2.xi;
}
void InsertNetListToAet(int y)
{
    for (list<Edge>::iterator it1 = slNet[y].begin(); it1 != slNet[y].end(); ++it1)
    {
        //cout << it1->xi << " " << it1->dx << " " << it1->ymax << endl; 
        aet.push_back(*it1);
    }
    aet.sort(EdgeXiComparator);
}

void FillAetScanLine(int y)
{
    bool flag;
    flag = true;
    list<Edge>::iterator it1;
    for (list<Edge>::iterator it = aet.begin(); it != aet.end(); it++)
    {
        it1 = it;
        it1++;
        if (it1 == aet.end())
        {
            break;
        }
        if (flag)
        {
            drawLine(it->xi, y, it1->xi, y);
        }
        flag = !flag;
    }
    glFlush();
}

//bool IsEdgeOutOfActive(Edge e, int y)
//{
//  return (e.ymax == y);
//}

void ProcessScanLineFill()
{
    aet.clear();
    for (int y = ymin; y <= ymax; y++)
    {
        InsertNetListToAet(y);
        FillAetScanLine(y);
        //删除非活动边
        for (list<Edge>::iterator it = aet.begin(); it != aet.end();)
        {
            if (it->ymax == y)
            {
                it = aet.erase(it);
            }
            else
            {
                it++;
            }
        }

        //更新活动边表中每项的xi值,并根据xi重新排序
        //更新xi  
        for (list<Edge>::iterator iter = aet.begin(); iter != aet.end(); iter++)
            iter->xi += iter->dx;
        //根据xi从小到大重新排序    
        aet.sort(EdgeXiComparator);
    }
}
void draw()
{
    initScanLineNewEdgeTable();
    HorizonEdgeFill();
    ProcessScanLineFill();
}
void init()
{
    //glClearColor(0.0, 0.0, 0.0, 0.0);
    //glShadeModel(GL_FLAT);
}
void display()
{
    int k;
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0.0, 1.0, 0.0);
    glBegin(GL_POINTS);
    for (k = 0; k < pointn; k++)
    {
        glVertex2i(verteces[k][0], verteces[k][1]);
    }
    glEnd();
    if (begin_to_draw == GL_TRUE)
    {
        glColor3f(0.0, 1.0, 1.0);
        draw();
    }
    glutSwapBuffers();
    //glFlush();
}
void keyboard(unsigned char key, int x, int y)
{
    switch (key){
    case 'r':
    case 'R':
        pointn = 0;
        finish_picking_points = GL_FALSE;
        begin_to_draw = GL_FALSE;
        break;
    case 'b':
    case 'B':
        begin_to_draw = GL_FALSE;
        break;
    case 'n':
    case 'N':
        begin_to_draw = GL_TRUE;
        break;
    };
    glutPostRedisplay();
}


//测试使用
//int xx[4] = { 0, 4, 10 };
//int yy[4] = { 0, 6, 4 };


void mouse(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
        if (finish_picking_points == GL_FALSE)      //如果是按下鼠标左键
        {
            verteces[pointn][0] = x;                //记录按下的点的x坐标       
            verteces[pointn][1] = windowheight - y; //记录按下的点的y坐标,由于坐标系原点一个是在左上角,一个是在左下角,所以要用windowheight-y。
            /*verteces[pointn][0] = xx[pointn];
            verteces[pointn][1] = yy[pointn];*/
            pointn++;
        }
    }
    else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) //如果是按下鼠标右键
    {
        newPloygon();   //构建多边形
        finish_picking_points = GL_TRUE; //停止画点
        begin_to_draw = GL_TRUE; //开始填充
    }
    glutPostRedisplay();
}

void reshape(int w, int h)
{
    windowwidth = w;
    windowheight = h;
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h);
}

int main(int argc, char ** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(windowwidth, windowheight);
    glutInitWindowPosition(300, 300);
    glutCreateWindow("扫描线算法");
    //init();
    glutDisplayFunc(display);
    glutMouseFunc(mouse);
    glutKeyboardFunc(keyboard);
    glutReshapeFunc(reshape);
    glutMainLoop();

    return 0;
}

这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

多边形区域填充算法--扫描线填充算法(有序边表法)

二、扫描线算法(Scan-Line Filling)         扫描线算法适合对矢量图形进行区域填充,只需要直到多边形区域的几何位置,不需要指定种子点,适合计算机自动进行图形处理的场合...

扫描线填充多边形算法详解与代码

扫描线填充多边形算法详解与代码首先给出已知信息:多边形结构体里面包含三个信息:顶点个数,顶点和颜色class MyPolygon { public: int m_VerticeNumber;...

算法系列之十二:多边形区域填充算法--扫描线填充算法(有序边表法)

二、扫描线算法(Scan-Line Filling)        扫描线算法适合对矢量图形进行区域填充,只需要直到多边形区域的几何位置,不需要指定种子点,适合计算机自动进行图形处理的场合使用,比如电...
  • orbit
  • orbit
  • 2012年03月19日 14:57
  • 66057

【图像处理】边相关扫描线填充算法

接着上篇博文《 多边形的扫描转换》 转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7712451 多边形 边相关扫描线填充算法需...

计算机图形学(三)扫描线多边形填充算法讲解与源代码

如果喜欢转载请标明出处: 并非菜鸟菜鸟的博客 源代码下载:点击打开链接 在这里先说下算法的实现过程 本人觉得这个算法实现起来还是有点难度的!很多人都不愿意去看太多描述性的文字,所以对这个算法的过程是...

扫描线填充算法(1)

参考网址:http://blog.csdn.net/orbit/article/details/7368996 http://wenku.baidu.com/view/4ee141347c1cfad...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

opengl实现直线扫描算法和区域填充算法

1、 采用直线扫描算法绘制一条线段,直线由离散点组成 2、 利用区域填充算法绘制多边形区域,区域由离散点组成...

多边形区域填充算法--扫描线种子填充算法

http://blog.csdn.net/orbit/article/details/7343236   1.3扫描线种子填充算法         1.1和1.2节介绍的两种种子填充算法的优点是...

关于扫描线的一些理解

关于扫描线这个东西,其实是不太好开始学习的,因为百度到的东西大部分是比较高深,或者是和计算几何相关的东西。 感觉稍微写点自己的理解吧…… 一、关于扫描线 关于扫描线这个东西,其实...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:扫描线填充算法(2)
举报原因:
原因补充:

(最多只允许输入30个字)