2D中多边形裁剪算法

该算法提供了一种良好的解决方案,主要的问题在于 long 值到 float 值的转换,在实际应用中,将使用 float 值作为输入。

/********************************************************************
    created:    19:10:2008   23:43
    filename:     los-prj/ClipTriangle/ClipTriangle.cpp
    author:        Zhipeng Wang
   
    purpose:   
*********************************************************************/

#include <Los/Los.h>
#include <Los/Blaze.h>

using namespace los::stringtypes;
using namespace los::framework;
using namespace los::controls;
using namespace los::blaze;
using namespace los::mathtools;

class CustomRender
    : public GDIRender
{
public:
    CustomRender()
        : _Cnt(0)
    {
    }

    virtual int Rendering()
    {
        LockSurface(0);
       
        size_t nLoop = 1;

        while (nLoop--)
            _DrawTriangle();

        UnlockSurface();

        tstringstream ss;
        ss << t("Frames: ") << _Cnt++;
        DrawText(Point(50, 50), ss.str());

        return GDIRender::Rendering();
    }

private:
    void _DrawTriangle()
    {
        Rect boundary = GetRect();

        Random<long> rnd;
        Point a(rnd(boundary.right), rnd(boundary.bottom));
        Point b(rnd(boundary.right), rnd(boundary.bottom));
        Point c(rnd(boundary.right), rnd(boundary.bottom));

        boundary.Inflate(-120, -120);
        /*
        SetFrameColor(0x9999CC);
        DrawLine(a, b);
        DrawLine(b, c);
        DrawLine(c, a);

        Point aa(boundary.left, boundary.top);
        Point ab(boundary.right, boundary.top);
        Point ba(boundary.left, boundary.bottom);
        Point bb(boundary.right, boundary.bottom);

        SetFrameColor(0xCCCCCC);
        DrawLine(aa, ab);
        DrawLine(ab, bb);
        DrawLine(bb, ba);
        DrawLine(ba, aa);
        //*/

        Point arr0[6];
        Point arr1[6];

        Point* src = arr0;
        Point* dest = arr1;

        src[0] = a, src[1] = b, src[2] = c;
        size_t nSrc = 3, nDest = 0;

        Point* p1_ptr;
        bool p1_put = false;

        for (size_t idx = 0; idx < nSrc; ++idx)
        {
            Point& p0 = src[idx];
            p1_ptr = &src[idx + 1];
            if (idx == nSrc - 1) p1_ptr = &src[0];
            Point& p1 = *p1_ptr;

            if (p0.x < boundary.left && p1.x < boundary.left) continue;

            if (p0.x > boundary.left && p1.x > boundary.left) {
                if (!p1_put) dest[nDest++] = p0;
                if (idx != nSrc - 1) dest[nDest++] = p1, p1_put = true;
                else p1_put = false;
                continue; }

            if (!p1_put && p0.x > boundary.left) dest[nDest++] = p0;

            float distance = (float)p1.x - (float)p0.x;
            float t = abs(distance) > Epsilon ? ((float)boundary.left - (float)p0.x) / distance : 0;
            Point p((long)((float)p0.x + ((float)p1.x - (float)p0.x) * t)
                , (long)((float)p0.y + ((float)p1.y - (float)p0.y) * t));
            dest[nDest++] = p;

            if (p1.x > boundary.left && idx != nSrc - 1)
                p1_put = true, dest[nDest++] = p1;
            else p1_put = false;
        }

        nSrc = nDest, nDest = 0;
        std::swap(src, dest);
        p1_put = false;

        for (size_t idx = 0; idx < nSrc; ++idx)
        {
            Point& p0 = src[idx];
            p1_ptr = &src[idx + 1];
            if (idx == nSrc - 1) p1_ptr = &src[0];
            Point& p1 = *p1_ptr;

            if (p0.y < boundary.top && p1.y < boundary.top) continue;

            if (p0.y > boundary.top && p1.y > boundary.top) {
                if (!p1_put) dest[nDest++] = p0;
                if (idx != nSrc - 1) dest[nDest++] = p1, p1_put = true;
                else p1_put = false;
                continue; }

            if (!p1_put && p0.y > boundary.top) dest[nDest++] = p0;

            float distance = (float)p1.y - (float)p0.y;
            float t = abs(distance) > Epsilon ? ((float)boundary.top - (float)p0.y) / distance : 0;
            Point p((long)((float)p0.x + ((float)p1.x - (float)p0.x) * t)
                , (long)((float)p0.y + ((float)p1.y - (float)p0.y) * t));
            dest[nDest++] = p;

            if (p1.y > boundary.top && idx != nSrc - 1)
                p1_put = true, dest[nDest++] = p1;
            else p1_put = false;
        }

        nSrc = nDest, nDest = 0;
        std::swap(src, dest);
        p1_put = false;

        for (size_t idx = 0; idx < nSrc; ++idx)
        {
            Point& p0 = src[idx];
            p1_ptr = &src[idx + 1];
            if (idx == nSrc - 1) p1_ptr = &src[0];
            Point& p1 = *p1_ptr;

            if (p0.x > boundary.right && p1.x > boundary.right) continue;

            if (p0.x < boundary.right && p1.x < boundary.right) {
                if (!p1_put) dest[nDest++] = p0;
                if (idx != nSrc - 1) dest[nDest++] = p1, p1_put = true;
                else p1_put = false;
                continue; }

            if (!p1_put && p0.x < boundary.right) dest[nDest++] = p0;

            float distance = (float)p1.x - (float)p0.x;
            float t = abs(distance) > Epsilon ? ((float)boundary.right - (float)p0.x) / distance : 0;
            Point p((long)((float)p0.x + ((float)p1.x - (float)p0.x) * t)
                , (long)((float)p0.y + ((float)p1.y - (float)p0.y) * t));
            dest[nDest++] = p;

            if (p1.x < boundary.right && idx != nSrc - 1)
                p1_put = true, dest[nDest++] = p1;
            else p1_put = false;
        }

        nSrc = nDest, nDest = 0;
        std::swap(src, dest);
        p1_put = false;

        for (size_t idx = 0; idx < nSrc; ++idx)
        {
            Point& p0 = src[idx];
            p1_ptr = &src[idx + 1];
            if (idx == nSrc - 1) p1_ptr = &src[0];
            Point& p1 = *p1_ptr;

            if (p0.y > boundary.bottom && p1.y > boundary.bottom) continue;

            if (p0.y < boundary.bottom && p1.y < boundary.bottom) {
                if (!p1_put) dest[nDest++] = p0;
                if (idx != nSrc - 1) dest[nDest++] = p1, p1_put = true;
                else p1_put = false;
                continue; }

            if (!p1_put && p0.y < boundary.bottom) dest[nDest++] = p0;

            float distance = (float)p1.y - (float)p0.y;
            float t = abs(distance) > Epsilon ? ((float)boundary.bottom - (float)p0.y) / distance : 0;
            Point p((long)((float)p0.x + ((float)p1.x - (float)p0.x) * t)
                , (long)((float)p0.y + ((float)p1.y - (float)p0.y) * t));
            dest[nDest++] = p;

            if (p1.y < boundary.bottom && idx != nSrc - 1)
                p1_put = true, dest[nDest++] = p1;
            else p1_put = false;
        }

        if (nDest < 3)
            return;

        for (size_t idx = 1; idx < nDest - 1; ++idx)
        {
            Point& p0 = dest[0];
            Point& p1 = dest[idx];
            Point& p2 = dest[idx + 1];

            DrawLine(p0, p1);
            DrawLine(p1, p2);
            DrawLine(p2, p0);
        }
    }

private:
    int _Cnt;
    Pipeline pipeline;
    DeviceBitmap dbm;
};

class RenderWnd
    : public Window
{
public:
    InheritClass(RenderWnd);

    RenderWnd()
        : Window(t("los::Gouraud::RenderWnd"), t("Gouraud"))
    {
        SetSize(def, def, 640, 480);
        AppStyle(wsMaximizeBox | wsThickFrame, true);
        SetClassBrush(Brush::brushBlack);
    }

    virtual void Create(Window* parent_)
    {
        Base::Create(parent_);
        render.InitRender(this, GetClientRect(), GetClientRect());
    }

    virtual bool RealTime()
    {
        render.BeginRender(false);
        render.Rendering();
        render.EndRender();

        Sleep(0);
        return true;
    }

private:
    CustomRender render;
};

Application app;

INT WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE, LPTSTR lpCmdLine, int nShowCmd)
{
    app.SetInstance(hInst);

    RenderWnd* pWnd = new RenderWnd;
    pWnd->Create(0);
    pWnd->ShowWindow();
    pWnd->UpdateWindow();

    app.Initialize(pWnd);
    return app.Run(0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值