Click here to Skip to main content
15,885,546 members
Articles / Web Development / HTML

Rotate Your Graphics - Advanced Memory Device Context

Rate me:
Please Sign up or sign in to vote.
4.75/5 (7 votes)
17 Jan 2000 121.1K   4K   43  
A memory DC that allows you to rotate your graphics
// cdxCRot90DC.h: interface for the cdxCRot90DC class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_CDXCROT90DC_H__BB122324_D85E_11D2_BF3F_000000000000__INCLUDED_)
#define AFX_CDXCROT90DC_H__BB122324_D85E_11D2_BF3F_000000000000__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

//
// cdxCRot90DC.h : header file
// -----------------------------------------------------------------------
// Author:  Hans B�hler (hans.buehler@student.hu-berlin.de)
//          codex design (http://www-pool.mathematik.hu-berlin.de/~codex
// Modified by: Leo Goodstadt (lg@ndirect.co.uk)
// Version: 1.1
// Release: 1 (Mar 1999 to www.codeguru.com)
// Notes:   This is an advanced version of the CMemDC class that has
//				been published by Keith Rule (even at codeguru's).
// -----------------------------------------------------------------------
// Comments welcome.
//

/*
 * cdxCRot90DC
 * ===========
 * A memory device context that allows to rotate output in 90 degree increments
 * Based on CMemDC by Keith Rule - you can find this DC on codeguru as well.
 *
 * The documentation for usage information.
 *
 * (w)Mar.1999 Hans B�hler, codex design
 *    mailto:hans.buehler@student.hu-berlin.de
  */

class cdxCRot90DC : public CDC  
{
	DECLARE_DYNAMIC(cdxCRot90DC);

public:
	enum Angle
	{
		a0		=	0,
	//	a360	=	a0,
		a90	=	1,
		a180	=	2,
		a270	=	3,
		a_num	=	4
	};

	enum DrawControlFlags
	{
		DRC_DISABLED			=	0x01,		// draw disabled
		DRC_NO_ICON_ROTATION	=	0x02		// don't rotate icon
	};

	enum
	{
		DRAWTEXT_HPOS			=	DT_LEFT|DT_RIGHT|DT_CENTER,
		DRAWTEXT_VPOS			=	DT_TOP|DT_BOTTOM|DT_VCENTER
	};

protected:
	typedef POINT	PLGBLTPNTS[3];

private:
	struct Rotator
	{
		int	m_iSin,m_iCos;

	public:
		long X(long x, long y) const { return x*m_iCos + y*m_iSin; }
		long Y(long x, long y) const { return y*m_iCos - x*m_iSin; }
		CSize Size(const CSize & sz) const { if(!m_iCos) return sz; return CSize(sz.cy,sz.cx); }
	};

private:
	CDC		*m_pDC;
	CRect		m_rectMine,m_rectMineClipped,
				m_rectDC,m_rectDCClipped;
	Angle		m_Angle;
	CBitmap	m_Bitmap;
	CBitmap	m_RotBitmap;
	LPDWORD	m_RotBytes;
	LPDWORD	m_Bytes;
	CSize		m_szBitmap;
	bool		m_bFinished;

	// device context storings
	int		m_iOldBkColor,m_iOldBkMode,m_iOldTextColor;
	CFont		*m_pOldFont;
	CBitmap	*m_pOldBitmap;

public:
	cdxCRot90DC() : m_pDC(NULL), m_bFinished(true) {}
	cdxCRot90DC(CDC & destDC, const CRect & rectDC, int iAngle, bool bCopy = false) : m_pDC(NULL), m_bFinished(true) { Create(destDC,rectDC,iAngle,bCopy); }
	cdxCRot90DC(CDC *pDC, const CRect & rectDC, int iAngle, bool bCopy = false) : m_pDC(NULL), m_bFinished(true) { Create(pDC,rectDC,iAngle,bCopy); }
	cdxCRot90DC(CDC & destDC, int iAngle, bool bCopy = false) : m_pDC(NULL), m_bFinished(true) { VERIFY( Create(destDC,iAngle,bCopy) ); }
	cdxCRot90DC(CDC *pDC, int iAngle, bool bCopy = false) : m_pDC(NULL), m_bFinished(true) { VERIFY( Create(pDC,iAngle,bCopy) ); }
	virtual ~cdxCRot90DC() { if(!m_bFinished) Finish(); Destroy(); }

	//
	// create & destroy
	//

	bool IsCreated() const { return m_pDC != NULL; }
	const CRect & GetRotRect() const { return m_rectMine; }

	bool Create(CDC & destDC, const CRect & rectDC, int iAngle, bool bCopy = false);
	bool Create(CDC * pDC, const CRect & rectDC, int iAngle, bool bCopy = false);
	bool Create(CDC & destDC, int iAngle, bool bCopy = false);
	bool Create(CDC * pDC, int iAngle, bool bCopy = false);
	bool Finish();
	void Invalidate() { m_bFinished = true; if(m_pDC && m_hDC) IntersectClipRect(CRect(0,0,0,0)); }
	void Destroy();

	//
	// copy from one DC to the other
	//

	void CopyTo(const CRect & rectDC) { CopyRotTo(rotate(rectDC)); }
	void CopyFrom(const CRect & rectDC);
	void CopyRotTo(const CRect & rectRotDC);
	void CopyRotFrom(const CRect & rectRotDC) { CopyFrom(rotateBack(rectRotDC)); }

	//
	// used to rotate my stuff
	// Forward rotation: Original DC -> Rot90 DC
	// Backward          Rot90 DC -> Original DC
	//

	CRect rotate(const CRect & r) const { return rotate(r,m_Angle); }
	CPoint rotate(const CPoint & p) const { return rotate(p,m_Angle); }
	CSize rotate(const CSize & s) const { return rotate(s,m_Angle); }
	void rotate(POINT *pPnts, UINT nCnt) const { rotate(pPnts,nCnt,m_Angle); }

	CRect rotateBack(const CRect & r) const { return rotate(r,inv(m_Angle)); }
	CPoint rotateBack(const CPoint & p) const { return rotate(p,inv(m_Angle)); }
	CSize rotateBack(const CSize & s) const { return rotate(s,inv(m_Angle)); }
	void rotateBack(POINT *pPnts, UINT nCnt) const { rotate(pPnts,nCnt,inv(m_Angle)); }

	//
	// some operators to use this DC as a pointer
	//

	operator cdxCRot90DC * () { return m_pDC ? this : NULL; }
	operator const CRect & () const { return GetRotRect(); }
	cdxCRot90DC *operator->() { ASSERT(IsCreated()); return this; }
	const cdxCRot90DC *operator->() const { ASSERT(IsCreated()); return this; }

	//
	// simple rotation
	//

	CRect operator()(const CRect & r, bool bFwd = true) const { return bFwd ? rotate(r) : rotateBack(r); }
	CPoint operator()(const CPoint & p, bool bFwd = true) const { return bFwd ? rotate(p) : rotateBack(p); }
	CSize operator()(const CSize & sz, bool bFwd = true) const { return bFwd ? rotate(sz) : rotateBack(sz); }
	void operator()(POINT *pPnts, UINT nCnt, bool bFwd = true) const { if(bFwd) rotate(pPnts,nCnt); else rotateBack(pPnts,nCnt); }

	//
	// static members
	//

	static CRect rotate(const CRect & r, int iAngle) { return rotate(r,mkAngle(iAngle)); }
	static CPoint rotate(const CPoint & p, int iAngle) { return rotate(p,mkAngle(iAngle)); }
	static CSize rotate(const CSize & s, int iAngle) { return rotate(s,mkAngle(iAngle)); }
	static void rotate(POINT *pPnts, UINT nCnt, int iAngle) { rotate(pPnts,nCnt,mkAngle(iAngle)); }

	static CRect rotate(const CRect & r, Angle iAngle);
	static CPoint rotate(const CPoint & p, Angle iAngle);
	static CSize rotate(const CSize & s, Angle iAngle);
	static void rotate(POINT *pPnts, UINT nCnt, Angle iAngle);

	static Angle inv(Angle a) { return a ? (Angle)(a_num - a) : a; }
	static Angle mkAngle(int iAngle);
	static int mkAngle(Angle a) { return a * 90; }

	//
	// further utility functions
	//

	void DrawControl(CString strText, HICON hIcon, UINT nDrawTextFlags = DT_CENTER|DT_VCENTER, UINT nMyFlags = 0, UINT nIconDist = 2) { DrawControl(m_rectMine,strText,hIcon,nDrawTextFlags,nMyFlags,nIconDist); }
	void DrawControl(CString strText, UINT nDrawTextFlags = DT_CENTER|DT_VCENTER, UINT nMyFlags = 0, UINT nIconDist = 2)  { DrawControl(m_rectMine,strText,NULL,nDrawTextFlags,nMyFlags,nIconDist); }
	void DrawControl(CRect rect, CString strText, HICON hIcon, UINT nDrawTextFlags = DT_CENTER|DT_VCENTER, UINT nMyFlags = 0, UINT nIconDist = 2);
	void DrawControl(CRect rect, CString strText, UINT nDrawTextFlags = DT_CENTER|DT_VCENTER, UINT nMyFlags = 0, UINT nIconDist = 2) { DrawControl(rect,strText,NULL,nDrawTextFlags,nMyFlags,nIconDist); }
	static CSize GetBitmapSize(HBITMAP hbmp);
	static CSize GetIconSize(HICON hIcon);

	//
	// protected members
	//
protected:
	static void PrePlgBlt(const CRect & rectSrc, PLGBLTPNTS & pnts, Angle iAngle);

	//
	// static member variables
	//
public:
	static const Rotator M_Rotator[a_num];
};

//////////////////////////////////////////////////////////////////////
// inlines
//////////////////////////////////////////////////////////////////////

/*
 * creation
 */

inline bool cdxCRot90DC::Create(CDC * pDC, const CRect & rectDC, int iAngle, bool bCopy)
{
	if(!pDC)
	{
		m_rectMine.SetRectEmpty();
		return false;
	}
	return Create(*pDC,rectDC,iAngle,bCopy);
}

/*
 * creation with current clip rect
 */

inline bool cdxCRot90DC::Create(CDC * pDC, int iAngle, bool bCopy)
{
	if(!pDC)
	{
		m_rectMine.SetRectEmpty();
		return false;
	}
	return Create(*pDC,iAngle,bCopy);
}

inline bool cdxCRot90DC::Create(CDC & destDC, int iAngle, bool bCopy)
{
	CRect	rect;destDC.GetClipBox(rect);
	return Create(destDC,rect,iAngle,bCopy);
}

/*
 * convert rectangle coords to rotated coords
 */

inline CRect cdxCRot90DC::rotate(const CRect & r, cdxCRot90DC::Angle iAngle)
{
	// BEGIN Added by LG 
	if (iAngle == a0 || iAngle == a180)
		return r;
	else
	{
		CPoint mid = r.CenterPoint();
		CSize Sz(r.Height(), r.Width());
		mid.Offset(-Sz.cx / 2, -Sz.cy / 2);
		return CRect(mid, Sz);
	}
	// END Added by LG 

/*	// removed by LG

	const Rotator	& rot	=	M_Rotator[iAngle];
	CRect	rect;

	rect.left	=	rot.X(r.left,r.top);
	rect.top	=	rot.Y(r.left,r.top);
	rect.right	=	rot.X(r.right,r.bottom);
	rect.bottom	=	rot.Y(r.right,r.bottom);

	long	l;
	if(rect.left > rect.right)
	{
		l	=	rect.left;
		rect.left	=	rect.right;
		rect.right	=	l;
	}
	if(rect.top > rect.bottom)
	{
		l	=	rect.top;
		rect.top		=	rect.bottom;
		rect.bottom	=	l;
	}
	return rect;
*/
}

inline CPoint cdxCRot90DC::rotate(const CPoint & p, cdxCRot90DC::Angle iAngle)
{
	ASSERT(0);
	CPoint	pnt;
	pnt.x			=	M_Rotator[iAngle].X(p.x,p.y);
	pnt.y			=	M_Rotator[iAngle].Y(p.x,p.y);
	return pnt;
}

inline CSize cdxCRot90DC::rotate(const CSize & sz, cdxCRot90DC::Angle iAngle)
{
	// BEGIN Added by LG 
	ASSERT(0);
	if (iAngle == a0 || iAngle == a180)
		return sz;
	else
		return CSize(sz.cy, sz.cx);
	// END Added by LG 
/*	// removed by LG
	return M_Rotator[iAngle].Size(sz);
*/
}

inline void cdxCRot90DC::rotate(POINT *pPnts, UINT nCnt, cdxCRot90DC::Angle iAngle)
{
	ASSERT(0);
	CPoint			p;
	const Rotator	& r	=	M_Rotator[iAngle];

	for(;nCnt>0; --nCnt, ++pPnts)
	{
		p			=	*pPnts;
		pPnts->x	=	r.X(p.x,p.y);
		pPnts->y	=	r.Y(p.x,p.y);
	}
}

//////////////////////////////////////////////////////////////////////

/*
 * convert 90� angle to Angle code
 */

inline cdxCRot90DC::Angle cdxCRot90DC::mkAngle(int iAngle)
{
	iAngle	/=	90;
	iAngle	%=	a_num;
	if(iAngle < 0)
		iAngle	+=	a_num;
	return (Angle)iAngle;
}

//////////////////////////////////////////////////////////////////////

/*
 * calculate stuff for PlgBlt
 */

inline void cdxCRot90DC::PrePlgBlt(const CRect & rectSrc, PLGBLTPNTS & pnts, Angle iAngle)
{
	pnts[0].x	=	rectSrc.left;
	pnts[0].y	=	rectSrc.top;
	pnts[1].x	=	rectSrc.right;
	pnts[1].y	=	rectSrc.top;
	pnts[2].x	=	rectSrc.left;
	pnts[2].y	=	rectSrc.bottom;

	rotate((POINT *)pnts,3,iAngle);
}

//////////////////////////////////////////////////////////////////////

/*
 * two nice helpers
 */

inline CSize cdxCRot90DC::GetBitmapSize(HBITMAP hbmp)
{
	BITMAP	bmp;
	bmp.bmWidth	=	bmp.bmHeight	=	0;

	VERIFY( ::GetObject(hbmp,sizeof(BITMAP),&bmp) );
	return CSize(bmp.bmWidth,bmp.bmHeight);
}

inline CSize cdxCRot90DC::GetIconSize(HICON hIcon)
{
	ICONINFO	ii;

	VERIFY( ::GetIconInfo(hIcon,&ii) );
	return GetBitmapSize(ii.hbmColor);
}

//////////////////////////////////////////////////////////////////////
// Blitting stuff around
//////////////////////////////////////////////////////////////////////

/*
 * copy rectRotDC of this context to target context
 */
/*
inline void cdxCRot90DC::CopyRotTo(const CRect & rectRotDC)
{
	if(!m_pDC || rectRotDC.IsRectEmpty())
		return;

	if(m_Angle == a0)
	{
		m_pDC->BitBlt(	rectRotDC.left,
							rectRotDC.top,
							rectRotDC.Width(),
							rectRotDC.Height(),
							this,
							rectRotDC.left,
							rectRotDC.top,
							SRCCOPY);
	}
	else
	{
		PLGBLTPNTS	pnts;
		PrePlgBlt(rectRotDC,pnts,inv(m_Angle));

		::PlgBlt(	m_pDC->m_hDC,
						(const POINT *)&pnts,
						m_hDC,
						rectRotDC.left,
						rectRotDC.top,
						rectRotDC.Width(),
						rectRotDC.Height(),
						NULL,
						0,
						0);
	}
}

//
// fill this context with rectDC from target context
//

inline void cdxCRot90DC::CopyFrom(const CRect & rectDC)
{
	if(!m_pDC || rectDC.IsRectEmpty())
		return;

	if(m_Angle == a0)
	{
		BitBlt(	rectDC.left,
					rectDC.top,
					rectDC.Width(),
					rectDC.Height(),
					m_pDC,
					rectDC.left,
					rectDC.top,
					SRCCOPY);
	}
	else
	{
		PLGBLTPNTS	pnts;
		PrePlgBlt(rectDC,pnts,m_Angle);

		::PlgBlt(m_hDC,
					(const POINT *)&pnts,
					m_pDC->m_hDC,
					rectDC.left,
					rectDC.top,
					rectDC.Width(),
					rectDC.Height(),
					NULL,
					0,
					0);
	}
}

*/
#endif // !defined(AFX_CDXCROT90DC_H__BB122324_D85E_11D2_BF3F_000000000000__INCLUDED_)

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


Written By
Other JP Morgan Chase
Hong Kong Hong Kong
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions