该算法提供了一种良好的解决方案,主要的问题在于 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);
}