1. 程式人生 > >判斷直線與矩形相交

判斷直線與矩形相交

// 判斷點在有向直線的左側還是右側.
// 返回值:-1: 點線上段左側; 0: 點線上段上; 1: 點線上段右側
int PointAtLineLeftRight(CPoint ptStart, CPoint ptEnd, CPoint ptTest)
{
 ptStart.x -= ptTest.x;
 ptStart.y -= ptTest.y;
 ptEnd.x -= ptTest.x;
 ptEnd.y -= ptTest.y;

 int nRet = ptStart.x * ptEnd.y - ptStart.y * ptEnd.x;
 if (nRet == 0)
  return 0;
 else if (nRet > 0)
  return 1;
 else if (nRet < 0)
  return -1;

 return 0;
}

// 判斷兩條線段是否相交
BOOL IsTwoLineIntersect(CPoint ptLine1Start, CPoint ptLine1End, CPoint ptLine2Start, CPoint ptLine2End)
{
 int nLine1Start = PointAtLineLeftRight(ptLine2Start, ptLine2End, ptLine1Start);
 int nLine1End = PointAtLineLeftRight(ptLine2Start, ptLine2End, ptLine1End);
 if (nLine1Start * nLine1End > 0)
  return FALSE;

 int nLine2Start = PointAtLineLeftRight(ptLine1Start, ptLine1End, ptLine2Start);
 int nLine2End = PointAtLineLeftRight(ptLine1Start, ptLine1End, ptLine2End);

 if (nLine2Start * nLine2End > 0)
  return FALSE;

 return TRUE;
}

// 判斷線段是否與矩形相交
BOOL IsLineIntersectRect(CPoint ptStart, CPoint ptEnd, CRect rect)
{
 // Two point both are in rect
 if (rect.PtInRect(ptStart) && rect.PtInRect(ptEnd))
  return TRUE;

 // One point is in rect, another not.
 if (rect.PtInRect(ptStart) && !rect.PtInRect(ptEnd))
  return TRUE;
 if (!rect.PtInRect(ptStart) && rect.PtInRect(ptEnd))
  return TRUE;

 // Two point both aren't in rect
 if (IsTwoLineIntersect(ptStart, ptEnd, CPoint(rect.left, rect.top), CPoint(rect.left, rect.bottom)))
  return TRUE;
 if (IsTwoLineIntersect(ptStart, ptEnd, CPoint(rect.left, rect.bottom), CPoint(rect.right, rect.bottom)))
  return TRUE;
 if (IsTwoLineIntersect(ptStart, ptEnd, CPoint(rect.right, rect.bottom), CPoint(rect.right, rect.top)))
  return TRUE;
 if (IsTwoLineIntersect(ptStart, ptEnd, CPoint(rect.left, rect.top), CPoint(rect.right, rect.top)))
  return TRUE;

 return FALSE;
}

// 測試程式碼:
const int RECTSIZE = 20;
void CMainFrame::OnPaint() 
{
 CPaintDC dc(this); // device context for painting
 
 // TODO: Add your message handler code here
 
 CRect rcClient;
 GetClientRect(rcClient);
 CDC memDC;
 memDC.CreateCompatibleDC(&dc);
 CBitmap memBmp;
 memBmp.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height());
 CBitmap *pOldBmp = memDC.SelectObject(&memBmp);
 
 memDC.FillSolidRect(rcClient, RGB(255, 255, 255));
 
 // Draw rect
 CPoint pt;
 GetCursorPos(&pt);
 ScreenToClient(&pt);

 CRect rect;
 rect.left = pt.x - RECTSIZE / 2;
 rect.top = pt.y - RECTSIZE / 2;
 rect.right = rect.left + RECTSIZE;
 rect.bottom = rect.top + RECTSIZE;

 memDC.Draw3dRect(rect, RGB(0, 0, 0), RGB(0, 0, 0));

 // Draw line
 CPoint pt1(300, 200);
 CPoint pt2(500, 350);
 if (IsLineIntersectRect(pt1, pt2, rect))
  DrawArrowLine(memDC.m_hDC, &pt1, &pt2, 30, xAngle, RGB(128, 0, 255));
 else
  DrawArrowLine(memDC.m_hDC, &pt1, &pt2, 30, xAngle, RGB(0, 0, 0));

 dc.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &memDC, 0, 0, SRCCOPY);
 memDC.SelectObject(pOldBmp);


 // Do not call CWnd::OnPaint() for painting messages
}

void CMainFrame::OnMouseMove(UINT nFlags, CPoint point) 
{
 // TODO: Add your message handler code here and/or call default
 Invalidate();

 CWnd::OnMouseMove(nFlags, point);
}

BOOL CMainFrame::OnEraseBkgnd(CDC* pDC) 
{
 // TODO: Add your message handler code here and/or call default

 return TRUE;
}