第一个graham扫描法求的凸包程序

昨天发现邓俊辉译的计算几何上讲的凸包算法非常清晰简洁,今天也尝试写一个。
判断向量是左转还是右转,最简便的方法是用叉乘,叉乘小于0表示右转,=0表示共线,大于0表示左转。
在MFC上做的时候还要注意坐标的问题,逻辑上的上凸包画出来实际上是下凸包,下凸包对应于图上的上

凸包。

bool operator < (CPoint& pt1, CPoint& pt2)
{
long diff = pt1.x - pt2.x;
if (diff < 0)
{
return true;
}
else if (!diff)
{
return pt1.y < pt2.y;
}
else
{
return false;
}
}

bool operator ==(CPoint& pt1, CPoint& pt2)
{
return pt1.x == pt2.x && pt1.y == pt2.y;
}

void CConvexHullTestView::DrawPts(CDC* pDC)
{
for (std::vector<CPoint>::iterator itr = m_vecPts.begin(); itr != m_vecPts.end();

++itr)
{
pDC->Ellipse(itr->x - 3, itr->y - 3, itr->x + 3, itr->y + 3);
}
}

void CConvexHullTestView::OnDraw(CDC* pDC)
{
CConvexHullTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here

this->DrawPts(pDC);
if (!m_bDrawHull)
{
return;
}

std::sort(m_vecPts.begin(), m_vecPts.end());
std::unique(m_vecPts.begin(), m_vecPts.end());
if (m_vecPts.size() < 3)
{
m_bDrawHull = false;
return;
}

std::list<CPoint> lowerhull;
lowerhull.push_back(m_vecPts[0]);
lowerhull.push_back(m_vecPts[1]);
std::list<CPoint>::iterator itrlast, itrmid, itrfirst;
CPoint a, b;//向量a,b
long i;
for (i = 2; i < m_vecPts.size(); ++i)
{
lowerhull.push_back(m_vecPts[i]);
itrlast = lowerhull.end();
--itrlast;
while (lowerhull.size() >= 3)
{
itrmid = itrlast;
itrfirst = --itrmid;
--itrfirst;
a.x = itrmid->x - itrfirst->x;
a.y = itrmid->y - itrfirst->y;
b.x = itrlast->x - itrmid->x;
b.y = itrlast->y - itrmid->y;
if (a.x * b.y - a.y * b.x >= 0) //叉乘大于0向左转,=0共线
{
lowerhull.erase(itrmid);
}
else
{
break;
}
}
}

for (itrfirst = lowerhull.begin(), itrlast = itrfirst, ++itrlast; itrlast !=

lowerhull.end(); itrfirst = itrlast, ++itrlast)
{
pDC->MoveTo(*itrfirst);
pDC->LineTo(*itrlast);
}

std::list<CPoint> upperhull;
upperhull.push_back(m_vecPts[m_vecPts.size() - 1]);
upperhull.push_back(m_vecPts[m_vecPts.size() - 2]);
for (i = m_vecPts.size() - 3; i >= 0; --i)
{
upperhull.push_back(m_vecPts[i]);
itrlast = upperhull.end();
--itrlast;

while (upperhull.size() >= 3)
{
itrmid = itrlast;
itrfirst = --itrmid;
--itrfirst;

a.x = itrmid->x - itrfirst->x;
a.y = itrmid->y - itrfirst->y;
b.x = itrlast->x - itrmid->x;
b.y = itrlast->y - itrmid->y;
if (a.x * b.y - a.y * b.x >= 0) //叉乘大于0向左转,=0共线
{
upperhull.erase(itrmid);
}
else
{
break;
}
}
}

for (itrfirst = upperhull.begin(), itrlast = itrfirst, ++itrlast; itrlast !=

upperhull.end(); itrfirst = itrlast, ++itrlast)
{
pDC->MoveTo(*itrfirst);
pDC->LineTo(*itrlast);
}
}

CConvexHullTestView::CConvexHullTestView()
{
// TODO: add construction code here
m_bDrawHull = false;

m_vecPts.push_back(CPoint(200,300));
m_vecPts.push_back(CPoint(400,600));
m_vecPts.push_back(CPoint(500,30));
m_vecPts.push_back(CPoint(550,400));
m_vecPts.push_back(CPoint(600,130));
m_vecPts.push_back(CPoint(610,450));
m_vecPts.push_back(CPoint(740,530));
}

void CConvexHullTestView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
if (m_bDrawHull)
{
m_vecPts.clear();
m_bDrawHull = false;
}
m_vecPts.push_back(point);
this->Invalidate(TRUE);
}

void CConvexHullTestView::OnRButtonDblClk(UINT nFlags, CPoint point)
{
m_bDrawHull = true;
this->Invalidate(TRUE);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值