linecurve.cpp

来自「Windows 图形编程 书籍」· C++ 代码 · 共 482 行

CPP
482
字号
//-----------------------------------------------------------------------------------//
//              Windows Graphics Programming: Win32 GDI and DirectDraw               //
//                             ISBN  0-13-086985-6                                   //
//                                                                                   //
//  Written            by  Yuan, Feng                             www.fengyuan.com   //
//  Copyright (c) 2000 by  Hewlett-Packard Company                www.hp.com         //
//  Published          by  Prentice Hall PTR, Prentice-Hall, Inc. www.phptr.com      //
//                                                                                   //
//  FileName   : linecurve.cpp					                                     //
//  Description: Line/curve demo program, Chapter 8                                  //
//  Version    : 1.00.000, May 31, 2000                                              //
//-----------------------------------------------------------------------------------//

#define STRICT
#define _WIN32_WINNT 0x0500
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <assert.h>
#include <tchar.h>
#include <math.h>
#include <stdio.h>

#include "..\..\include\win.h"
#include "..\..\include\Canvas.h"
#include "..\..\include\Status.h"
#include "..\..\include\FrameWnd.h"
#include "..\..\include\Affine.h"
#include "..\..\include\Pen.h"
#include "..\..\include\curve.h"
#include "..\..\include\BezierCurve.h"

#include "Resource.h"


class KMyCanvas : public KCanvas
{
	virtual void    OnDraw(HDC hDC, const RECT * rcPaint);
	virtual LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	virtual	BOOL    OnCommand(WPARAM wParam, LPARAM lParam);

	int		m_test;
	int		m_lastx;
	int		m_lasty;

	void SetTest(int test);

	void DrawCrossHair(HDC hDC, bool on);

	void TestDrawMode(HDC hDC);
	void TestWidthCap(HDC hDC);
	void TestDCPen(HDC hDC);
	void TestPenStyle(HDC hDC);

	void TestCosmetic(HDC hDC);
	void TestGeometricWidth(HDC hDC);
	void TestGeometricStyle(HDC hDC);

	void TestLine1(HDC hDC);
	void TestLine2(HDC hDC);
	void TestBezier(HDC hDC);
	void BezierDemo(HDC hDC);

	void DragBezier(HDC hDC, int x, bool on);
	void TestBezierPen(HDC hDC);
	void TestArc(HDC hDC);

	void ArcToBezier(HDC hDC);
	void AngleArcToBezier(HDC hDC);

	void TestPath(HDC hDC);
	void TestPathStyleCurve(HDC hDC);

	void TestMapPath(HDC hDC);

	POINT m_bezier[4];

public:

	KMyCanvas()
	{
		m_test  = -1;
		m_lastx = -1;
		m_lasty = -1;

		m_bezier[0].x =  30; m_bezier[0].y = 330;
		m_bezier[1].x = 130; m_bezier[1].y =  30;
		m_bezier[2].x = 430; m_bezier[2].y = 130;
		m_bezier[3].x = 630; m_bezier[3].y = 430;
	}
};


void KMyCanvas::SetTest(int test)
{
	m_test = test;

	HMENU hMain = GetMenu(GetParent(m_hWnd));

	TCHAR Temp[MAX_PATH];

	_tcscpy(Temp, _T("LineCurve - "));

	GetMenuString(hMain, m_test, Temp + _tcslen(Temp), 
		sizeof(Temp)/sizeof(TCHAR) - _tcslen(Temp), MF_BYCOMMAND);

	SetWindowText(GetParent(m_hWnd), Temp);
}


BOOL KMyCanvas::OnCommand(WPARAM wParam, LPARAM lParam)
{
	switch ( LOWORD(wParam) )
	{
		case IDM_TEST_DRAWMODE:
		case IDM_TEST_WIDTHCAP:
		case IDM_TEST_DCPEN:
		case IDM_TEST_PENSTYLE:
		case IDM_TEST_COSMETIC:
		case IDM_TEST_GEOMETRIC_WIDTH:
		case IDM_TEST_GEOMETRIC_STYLE:
		case IDM_TEST_LINE1:
		case IDM_TEST_LINE2:
		case IDM_TEST_BEZIER:
		case IDM_TEST_BEZIERDEMO:
		case IDM_TEST_BEZIERPEN:
		case IDM_TEST_ARC:
		case IDM_TEST_ARCBEZIER:
		case IDM_TEST_ANGLEARCBEZIER:
		case IDM_TEST_PATH:
		case IDM_TEST_PATHSTYLECURVE:
		case IDM_TEST_MAPPATH:
			SetTest( LOWORD(wParam) );
			InvalidateRect(m_hWnd, NULL, TRUE);
			return TRUE;

		case IDM_FILE_EXIT:
			DestroyWindow(GetParent(m_hWnd));
			return TRUE;
	}

	return FALSE;	// not processed
}


void KMyCanvas::DrawCrossHair(HDC hDC, bool on)
{
	if ( (m_lastx<0) || (m_lasty<0) )
		return;

	if ( m_test == IDM_TEST_BEZIER )
		DragBezier(hDC, m_lastx, on);
	else
	{
		RECT rect;

		GetClientRect(m_hWnd, & rect);

		SetROP2(hDC, R2_XORPEN);
		KPen pen(PS_DOT, 0, RGB(0, 0, 0xFF), hDC);

		Line(hDC, rect.left, m_lasty, rect.right, m_lasty);
		Line(hDC, m_lastx, rect.top, m_lastx, rect.bottom);
	}
}


LRESULT KMyCanvas::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	LRESULT lr;

	switch( uMsg )
	{
		case WM_CREATE:
			m_hWnd = hWnd;
			SetTest(IDM_TEST_DRAWMODE);
			return 0;

		case WM_PAINT:
			{
				PAINTSTRUCT ps; 

//				SetLastError(0);
//				HRGN hrgnClip = CreateRectRgn(0,0,0,0);
//				GetUpdateRgn(m_hWnd,hrgnClip,FALSE);
//				HDC hdc = GetDCEx(m_hWnd,NULL,DCX_VALIDATE|DCX_INTERSECTUPDATE);

				HDC hDC = BeginPaint(m_hWnd, &ps);

			//	DrawCrossHair(hDC);
				OnDraw(hDC, &ps.rcPaint);
				DrawCrossHair(hDC, true);

				EndPaint(m_hWnd, &ps);
			}
			return 0;

		case WM_MOUSEMOVE:
			{
				HDC hDC = GetDC(hWnd);

				DrawCrossHair(hDC, false);
				m_lastx = LOWORD(lParam); m_lasty = HIWORD(lParam);
				DrawCrossHair(hDC, true);
				ReleaseDC(hWnd, hDC);
				
				TCHAR temp[32];
				wsprintf(temp, _T("(%d, %d)"), m_lastx, m_lasty);
				m_pStatus->SetText(0, temp);
		
			}
			return 0;

		default:
			lr = DefWindowProc(hWnd, uMsg, wParam, lParam);
	}

	return lr;
}


const TCHAR * R2_Names[] = 
{
	"R2_BLACK",
	"R2_NOTMERGEPEN",
	"R2_MASKNOTPEN",
	"R2_NOTCOPYPEN",
	"R2_MASKPENNOT",
	"R2_NOT",
	"R2_XORPEN",
	"R2_NOTMASKPEN",
	"R2_MASKPEN",
	"R2_NOTXORPEN",
	"R2_NOP",
	"R2_MERGENOTPEN",
	"R2_COPYPEN",
	"R2_MERGEPENNOT",
	"R2_MERGEPEN",
	"R2_WHITE"
};


void KMyCanvas::TestDrawMode(HDC hDC)
{
	for (int c=0; c<20; c++)
	{
		RECT rect = { c*20+40, 30, c*20+58, 400 };

		HBRUSH hBrush = CreateSolidBrush(PALETTEINDEX(c));

		FillRect(hDC, & rect, hBrush);

		DeleteObject(hBrush);
	}

	KPen pen(PS_SOLID, 0, RGB(0xFF, 0, 0), hDC);

	for (int r=R2_BLACK; r<=R2_WHITE; r++)
	{
		SetROP2(hDC, r);

		for (int i=0; i<18; i++)
		{
			Label(hDC, 440, r*22+20, R2_Names[r-R2_BLACK]);

			Line(hDC, 30, r*22+20+i, 430, r*22+20+i);
		}
	}
} 


void ZoomPixel(HDC hDC, int x0, int y0, int x1, int y1)
{
	COLORREF c = GetPixel(hDC, x0, y0);

	HBRUSH hBrush = CreateSolidBrush(c);
	SelectObject(hDC, hBrush);

	Rectangle(hDC, x1, y1, x1+11, y1+11);
	SelectObject(hDC, GetStockObject(WHITE_BRUSH));
	DeleteObject(hBrush);
}


void KMyCanvas::TestWidthCap(HDC hDC)
{
	char temp[6];

	KPen green(PS_SOLID, 0, RGB(0, 0xFF, 0));
	
	for (int i=0; i<12; i++)
	{
		KPen pen (PS_DOT, i, RGB(0, 0, 0xFF));

		int x0 = 40 + (i/2)*110;
		int x1 = x0 + 64;
		int y0 = 30 + (i & 1) * 200;
		
		// thick line
		Line(hDC, x0, y0, x1, y0, pen.m_hPen);

		// Center line
		Line(hDC, x0, y0, x1, y0, green.m_hPen);

		wsprintf(temp, "w=%d", i);
		Label(hDC, 40+x0-5*12, 90 + y0 -5*12-17, temp);

		// copy zoomed line
		for (int y=-5; y<6; y++)
		for (int x=-5; x<3;  x++)
			ZoomPixel(hDC, x0+x, y0+y, 40+x0+x*12, 90 + y0 + y*12);

		Line(hDC, x0, y0, x1, y0, pen.m_hPen);
	}
}


void KMyCanvas::TestDCPen(HDC hDC)
{
	Label(hDC, 10, 0, _T("Use DC_PEN to simulate gradient fill"));

	SelectObject(hDC, GetStockObject(DC_PEN));

	for (int i=0; i<128; i++)
	{
		SetDCPenColor(hDC, RGB(i, 255-i, 128+i));

		Line(hDC, 40, i+40, 150, i+40);
	}

	SelectObject(hDC, GetStockObject(BLACK_PEN));
	
	// Test DeleteObject on stock object
	BOOL rslt = DeleteObject(GetStockObject(DC_PEN));
}

const LPCTSTR mess_PenStyle [] =
{
	_T("PS_SOLID"),
	_T("PS_DASH"),
	_T("PS_DOT"),
	_T("PS_DASHDOT"),
	_T("PS_DASHDOTDOT"),
	_T("PS_NULL"),
	_T("PS_INSIDEFRAME"),
	_T("PS_USERSTYLE"),
	_T("PS_ALTERNATE")
};


void KMyCanvas::TestPenStyle(HDC hDC)
{
	// Pen style
	for (int i = PS_SOLID; i<=PS_INSIDEFRAME; i++)
	{
		Label(hDC, 10, i*20+10, mess_PenStyle[i]);

		SetBkColor(hDC, RGB(0, 0xFF, 0));
		SetBkMode(hDC, OPAQUE);

		{	
			KPen Pen(i, 1, RGB(0x00, 0x00, 0xFF), hDC);
		
			Line(hDC, 150, i*20 + 17, 180, i*20 + 17);
		}

		SetBkColor(hDC, RGB(0xFF, 0xFF, 0xFF));
	
		// copy to zoomed display
		for (int x=150; x<180; x++)
			ZoomPixel(hDC, x,                i*20 + 17,
				           200 + (x-150)*12, i*20 + 12);
	}
}


void KMyCanvas::TestCosmetic(HDC hDC)
{
	const LOGBRUSH logbrush = { BS_SOLID, RGB(0, 0, 0xFF), 0 };

//	SetMapMode(hDC, MM_ANISOTROPIC);
//	SetViewportExtEx(hDC, 2, 2, NULL);

	for (int i = PS_SOLID; i<=PS_ALTERNATE; i++)
	{
		HPEN hPen;
		const DWORD cycle[4] = { 4, 3, 2, 1 };
		
		if ( i==PS_USERSTYLE )
			hPen = ExtCreatePen(PS_COSMETIC | i, 1, & logbrush, 4, cycle);
		else
			hPen = ExtCreatePen(PS_COSMETIC | i, 1, & logbrush, 0, NULL);
		
		Label(hDC, 10, i*20+10, mess_PenStyle[i]);

		if ( hPen )
		{
			SelectObject(hDC, hPen);
			SetBkColor(hDC, RGB(0, 0xFF, 0));
			SetBkMode(hDC, OPAQUE);
		//	SetROP2(hDC, R2_XORPEN);

			// draw style line
			Line(hDC, 150, i*20 + 17, 180, i*20 + 17);

			SetBkColor(hDC, RGB(0xFF, 0xFF, 0xFF));
	
			SelectObject(hDC, GetStockObject(BLACK_PEN));
			DeleteObject(hPen);

			// copy to zoomed display
			for (int x=150; x<180; x++)
				ZoomPixel(hDC, x,                i*20 + 17,
					           200 + (x-150)*12, i*20 + 12);
		}
	}
}

void KMyCanvas::TestGeometricWidth(HDC hDC)
{
	const LOGBRUSH logbrush = { BS_SOLID, RGB(0, 0xFF, 0), 0 };

	int save = SaveDC(hDC);

	HPEN hGreen = CreatePen(PS_SOLID, 0, RGB(0, 0xFF, 0));

	SetBkColor(hDC, RGB(0, 0xFF, 0));
	SetBkMode(hDC, OPAQUE);

	// Geometric line width under transformation
	
		HPEN hPen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT, 61, & logbrush, 0, NULL);
		
		KAffine affine;

		POINT p[6] = { 0, 0, 200, 0, -00, -30, 200, -30, 200, 30, 0, 30 };

		affine.Rotate(30, 0, 0);
		affine.Translate(100, -200);

		SelectObject(hDC, hPen);
		SetMapMode(hDC, MM_ANISOTROPIC);
		SetViewportExtEx(hDC, 1, -1, NULL);

		SetGraphicsMode(hDC, GM_ADVANCED);

		SetWorldTransform(hDC, & affine.m_xm);

		LPtoDP(hDC, p, 6);

		Line(hDC, 0, 0, 200, 0);

		SelectObject(hDC, GetStockObject(BLACK_PEN));
		DeleteObject(hPen);

		ModifyWorldTransform(hDC, NULL, MWT_IDENTITY);
		SetGraphicsMode(hDC, GM_COMPATIBLE);

		SetBkColor(hDC, RGB(0xFF, 0xFF, 0xFF));
		SetTextAlign(hDC, TA_LEFT);

		SetViewportExtEx(hDC, 1, 1, NULL);

		Line(hDC, p[0].x, p[0].y, 20, 200);
		Label(hDC, 20, 200, "(x0,y0)");

		Line(hDC, p[1].x, p[1].y, 300, 80);
		Label(hDC, 300, 80, "(x1,y1)");

		Line(hDC, p[5].x, p[5].y, 20, 120);
		Label(hDC, 20, 120, "(x0-dx,y0+dy)");

		Line(hDC, p[4].x, p[4].y, 260, 40);
		Label(hDC, 260, 40, "(x1-dx,y1+dy)");

		Line(hDC, p[3].x, p[3].y, 300, 160);
		Label(hDC, 300, 160, "(x1+dx,y1-dy)");

		Line(hDC, p[2].x, p[2].y, 130, 250);
		Label(hDC, 130, 250, "(x0+dx,y0-dy)");

		Label(hDC, 20, 20, "dx = pen_width * sin(

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?