你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 图形图象处理与游戏编程
流动性蚂蚁线的设计(下)
 

五、蚂蚁线管理类

蚂蚁线管理类(CMarchingAntsManager)实现蚂蚁线的生成、删除、绘制(蚂蚁爬动)、暂停、属性修改等功能。

主要属性如表3所示。

3  蚂蚁线管理类属性

HWND hWnd

窗口句柄

ants_vector

蚂蚁线数组

HANDLE  m_hThread

线程句柄

HANDLE  m_hPause

暂停标志句柄

HANDLE  m_hExitEvent

退出事件句柄

bool        m_bIsInitialized

初始化标志

bool        m_bPause

暂停标志

CRITICAL_SECTION cs

互斥量

bool     b_UseGdiplus

使用GDIGDI++绘制

主要方法如表4所示:

4 蚂蚁线管理类方法

void Initialize()

初始化

bool InitAnimation()

开始流动

void SetPause(bool bPause)

是否暂停

void Destroy()

删除

void SetUseGdiplus(bool flag)

使用GDI++绘制标志

void Delete()

删除数据

bool Draw(void)

绘制

void ThreadAnimation()

启动动画线程

_ThreadAnimationProc(LPVOID)

动画线程

除此之外,还提供了多种蚂蚁线的加入函数,如点(PointPoints)、线(LineLines)、矩形(Rectangle)等基本图形蚂蚁线函数,通过其返回指针可修改各种蚂蚁线的属性。多个蚂蚁线存放在ants_vector蚂蚁线数组中。

1. 绘制线程

由于同时需要绘制的蚂蚁线有多个,蚂蚁线的绘制放在线程中实现,比采用定时器实现有更好的封装,绘制过程用ThreadAnimation线程实现,其关键的代码在Draw中实现。主要代码如下:

//对蚂蚁线数组进行循环

    for(……)

    {

        if(*iter)

        {

            if(b_UseGdiplus)//采用GDI++进行绘制

            {

//构造绘图对象

                Graphics graphics(hWnd);

                  //调用具体蚂蚁线绘制功能

                (*iter)->Draw(&graphics);

            }

            else//采用GDI进行绘制

            {

                  //得到绘图句柄

                HDC hDC=GetDC(hWnd);

                  //调用具体蚂蚁线绘制功能

                 (*iter)->Draw(hDC);

                  //释放绘图句柄

                ReleaseDC(hWnd,hDC);

            }

        }

    }

从这里看出,在各类蚂蚁线中实现了具体的绘制过程,管理起来就很容易,充分体现了C++重载的好处。

2.线程同步

由于采用了线程绘制蚂蚁线,同时还需要动态增加、删除蚂蚁线、修改蚂蚁线的属性、启动、退出等功能,这就涉及到线程同步问题,处理不好会出现不可预知的错误。

线程同步是多线程程序设计的核心内容,其目的是正确处理多线程并发时的各种问题,例如线程的等待、多个线程访问同一数据时的互斥,防死锁等。Win32提供多种内核对象和手段用于线程同步,如互斥量、信号量、事件、临界区等。所不同的是,互斥量、信号量、事件都是Windows的内核对象,当程序对这些对象进行控制时会自动转换到核心态,而临界区本身不是内核对象,它是工作在用户态的。从用户态转换到核心态是需要以时间为代价的,所以如果能在用户态就简单解决的问题,就可以不必劳烦核心态了。

临界区保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后,其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。

临界区包含两个操作原语:

EnterCriticalSection() 进入临界区

LeaveCriticalSection()离开临界区

EnterCriticalSection()语句执行后代码将进入临界区以后无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。否则临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。

在蚂蚁线实现的过程中,在访问数据时进行时都进行了以上操作,如修改蚂蚁线宽度的SetWidth()方法的实现:

void CMarchingAntsType::SetWidth(unsigned int w)

{

    EnterCriticalSection(&cs);

    width=w;

    LeaveCriticalSection(&cs);

}

线程的退出同步主要是通过信号事件实现,初始化时实现代码如下:

void CMarchingAntsManager::Initialize()

{

    m_hThread = NULL;

    m_bIsInitialized = false;

   

    m_bPause = false;

     //创建退出事件

    m_hExitEvent = CreateEvent(NULL,TRUE,FALSE,…);

    //创建暂停事件

m_hPause = CreateEvent(NULL,TRUE,TRUE,NULL);

}

退出时必须进行线程等待,主要代码如下:

void CMarchingAntsManager::Destroy()

{  

    if (m_hThread)

    {

        //如果是暂停,则停止暂停

        SetPause(false);

        SetEvent(m_hExitEvent);

     //等待绘制线程退出

        WaitForSingleObject(m_hThread, INFINITE);

    }

    //关闭相关句柄

CloseHandle(m_hThread);

    ……

}

    通过以上处理,程序运行稳定可靠。

六、结语

  虽然以上只实现了简单图形的蚂蚁线,但通过对CMarchingAntsType及相关继承类进行继承、重载绘制函数,可实现如椭圆、曲线等更加复杂蚂蚁线,实现的关键主要是将复杂图形进行离散化成折线,如对椭圆利用DDA算法、曲线可利用样条曲线生成算法,然后调用CMarchingAntsPolyLine的绘制方法即可实现各种复杂的蚂蚁线。

 

参考资料

 

[1]TroyHailey:TdhMarchingAnts[EB/OL],http://www.codeproject.com/KB/miscctrl/TdhMarchingAnts.aspx.

[2]Dimitri van Heesch:doxygen[EB/OL], http://www.stack.nl/~dimitri/doxygen/.

[3]Nicolai M.Josuttis,C++标准程序库[M],武汉华中科技大学出版社,2002

  推荐精品文章

·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089