📄 graphiteview.cpp
字号:
//
// Graphite For WinCE(Pocket PC)
// Initially Written By Hyouck "Hawk" Kim, peakhunt@yahoo.com
// 2002, All Rights Reserved
//
// This is GPLed, open source based, software development project.
// For more question about GPL,
// visit http://www.gnu.org/licenses/gpl.txt
//
//
// Revision History
// Nov/30/2002, Initial Release hkim
//
//
// graphiteView.cpp : implementation of the CGraphiteView class
//
//////////////////////////////////////////////////////////////////////
//
// This is View implementation of Graphite.
//
// If you are familiar with Win32 Memory DC and related stuffs,
// I guess to read this code would be pretty easy.
//
// But still, we have a few challenging, I guess, issues.
//
// First of all,
// Because of limited screen resolution, it's impossible to map each and every
// unique logical position to an unique screen pixel point.
// Because of this, sometimes, an ugly effect happens.
//
// Second of all,
// We have a performance issue.
// For example, for X axis, if the range is 8
// and if you want to use 0.01 value level X delta,
// It takes quite a time to draw the graph.
// For this problem, I guess we have no easy solution.
// Use of thread might look like a solution. But wait a minute.
// It doesn't solve any problem, that is, it doesn't make things faster.
//
// I guess the wise solution is just accept the fact and
// show some progress dialog while drawing graph.
//
//
// But Don't be so frustrated. Here are some good news.
// If we don't update screen because of mathematical change, that is, document change
// then we don't have to write a new same graph.
// That's because of I save all graph image in a memory device context.
//
// Here are some improvements need to be done.
// 1>We need scroll function.
// Currently, if an user scrolls left/right/up/down,
// the code reclaculates all points with a new X/Y values.
// But we don't have to do that.
// Better way is to draw only newly added area as a side effect of scrolling.
//
// Happy Graphying!!!
// H.Kim
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "graphite.h"
#include "graphiteDoc.h"
#include "graphiteView.h"
#include <math.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CGraphiteView
IMPLEMENT_DYNCREATE(CGraphiteView, CView)
BEGIN_MESSAGE_MAP(CGraphiteView, CView)
//{{AFX_MSG_MAP(CGraphiteView)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CGraphiteView construction/destruction
CGraphiteView::CGraphiteView()
{
// TODO: add construction code here
m_crBack = RGB(255, 255, 255); //white
m_crEdge = RGB( 0, 0, 0); //black
m_crTitle = RGB( 0, 0, 0); //black
m_crDotLine = RGB(255, 255, 0);
m_crPlot = RGB(255, 0, 0); //red
m_crXY = RGB(0 , 0, 0);
m_xTitle = L"X ";
m_yTitle = L"Y ";
m_brush.CreateSolidBrush(m_crBack);
}
CGraphiteView::~CGraphiteView()
{
}
BOOL CGraphiteView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CGraphiteView drawing
void CGraphiteView::OnDraw(CDC* pDC)
{
CGraphiteDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CRect rect;
GetClientRect(rect);
if(m_backDC.GetSafeHdc() == NULL)
DrawBackGround(pDC);
if(m_xyTitleDC.GetSafeHdc() == NULL)
DrawXYTitle(pDC);
if(m_graphDC.GetSafeHdc() == NULL)
DrawGraph(pDC);
pDC->BitBlt(0,0, rect.Width(), rect.Height(),
&m_graphDC, 0, 0, SRCCOPY);
}
/////////////////////////////////////////////////////////////////////////////
// CGraphiteView diagnostics
#ifdef _DEBUG
void CGraphiteView::AssertValid() const
{
CView::AssertValid();
}
void CGraphiteView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CGraphiteDoc* CGraphiteView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CGraphiteDoc)));
return (CGraphiteDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CGraphiteView message handlers
void CGraphiteView::DrawBackGround(CDC *dc)
{
CRect rect;
CPen penDot;
CPen penNormal;
CRect edge;
CPen *oldPen;
CGraphiteDoc* pDoc = GetDocument();
GetClientRect(rect);
if(m_backDC.GetSafeHdc() == NULL)
{
// first time
m_backDC.CreateCompatibleDC(dc);
m_backBitmap.CreateCompatibleBitmap(dc,
rect.Width(), rect.Height());
m_backDC.SelectObject(&m_backBitmap);
}
m_backDC.SetBkColor(m_crBack);
m_backDC.FillRect(rect, &m_brush);
//Draw Edge
GetPlotRect(edge, rect);
{
CPen penEdge;
penEdge.CreatePen(PS_SOLID, 0, m_crEdge);
oldPen = m_backDC.SelectObject(&penEdge);
m_backDC.DrawFocusRect(edge);
m_backDC.SelectObject(oldPen);
}
int cx, cy;
cx = (edge.left + edge.right)/2;
cy = (edge.top + edge.bottom)/2;
//draw dotted line
{
CPen penDot;
int pix_inc = edge.Width()/(NUM_MEASURE_PER_PAGE);
penDot.CreatePen(PS_DASH, 0, m_crDotLine);
oldPen = m_backDC.SelectObject(&penDot);
for(int i = 1; i < NUM_MEASURE_PER_PAGE; i++)
{
m_backDC.MoveTo(edge.left + i*pix_inc, edge.top);
m_backDC.LineTo(edge.left + i*pix_inc, edge.bottom);
m_backDC.MoveTo(edge.left, edge.top + i*pix_inc);
m_backDC.LineTo(edge.right, edge.top + i*pix_inc);
}
m_backDC.SelectObject(oldPen);
}
}
void CGraphiteView::GetPlotRect(CRect& edge, CRect& rect)
{
edge = rect;
edge.top += TOP_SPACE_IN_PIXEL;
edge.left += SIDE_SPACE_IN_PIXEL;
edge.right -= SIDE_SPACE_IN_PIXEL;
edge.bottom -= BOTTOM_SPACE_IN_PIXEL;
// practcally
// on wince
// it's impossible for width to be bigger than height.
if(edge.Width() < edge.Height())
{
int diff = edge.Height() - edge.Width();
edge.bottom -= diff;
}
}
int CGraphiteView::physicalX(double vx)
{
CGraphiteDoc* pDoc = GetDocument();
int x;
double range = (pDoc->m_maxX - pDoc->m_minX);
double diff = (vx - pDoc->m_minX);
double pct;
CRect rect,edge;
GetClientRect(rect);
GetPlotRect(edge, rect);
pct = (diff/range)*100;
if(pct < 0 || pct > 100)
return -1;
if(pct == 100)
x = edge.right;
else
x = edge.left + (int)((edge.Width())*pct/100);
return x;
}
int CGraphiteView::physicalY(double vy)
{
CGraphiteDoc* pDoc = GetDocument();
int y;
double range = (pDoc->m_maxY - pDoc->m_minY);
double diff = (vy - pDoc->m_minY);
double pct;
CRect rect,edge;
GetClientRect(rect);
GetPlotRect(edge, rect);
pct = (diff/range)*100;
if(pct < 0 || pct > 100)
return -1;
if(pct == 100)
y = edge.top;
else
y = edge.bottom - (int)((edge.Height())*pct/100);
return y;
}
void CGraphiteView::addPoint(double x, double y)
{
int px, py;
px = physicalX(x);
py = physicalY(y);
if(px < 0 || py < 0)
return;
}
void CGraphiteView::DrawXYTitle(CDC *pDC)
{
CRect rect;
CGraphiteDoc* pDoc = GetDocument();
GetClientRect(rect);
if(m_xyTitleDC.GetSafeHdc() == NULL)
{
// first time
m_xyTitleDC.CreateCompatibleDC(pDC);
m_xyTitleBitmap.CreateCompatibleBitmap(pDC,
rect.Width(), rect.Height());
m_xyTitleDC.SelectObject(&m_xyTitleBitmap);
}
m_xyTitleDC.SetBkColor(m_crBack);
m_xyTitleDC.FillRect(rect, &m_brush);
m_xyTitleDC.BitBlt(0, 0,
rect.Width(), rect.Height(),
&m_backDC, 0, 0, SRCCOPY);
//draw XY axis
CPen penXY, *oldPen;
CRect edge;
GetPlotRect(edge, rect);
penXY.CreatePen(PS_SOLID, 0, m_crXY);
oldPen = m_xyTitleDC.SelectObject(&penXY);
if(physicalY(0) != -1)
{
m_xyTitleDC.MoveTo(edge.left, physicalY(0));
m_xyTitleDC.LineTo(edge.right,physicalY(0));
}
if(physicalX(0) != -1)
{
m_xyTitleDC.MoveTo(physicalX(0), edge.top);
m_xyTitleDC.LineTo(physicalX(0), edge.bottom);
}
m_xyTitleDC.SelectObject(oldPen);
// draw title
{
CFont font, *oldFont;
CRect txtRect;
font.CreateFont(9,4,0, 0, 300,
FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH, L"Arial");
// draw title
oldFont = m_xyTitleDC.SelectObject(&font);
m_xyTitleDC.SetTextColor(m_crTitle);
txtRect.top = rect.top + 10;
txtRect.bottom = edge.bottom ;
txtRect.left = edge.left;
txtRect.right = edge.right;
m_xyTitleDC.DrawText(pDoc->m_plotTitle,
txtRect, DT_CENTER | DT_TOP);
// draw y title
txtRect.top = edge.bottom + 1;
txtRect.bottom = rect.bottom;
m_xyTitleDC.DrawText(m_yTitle,
txtRect, DT_CENTER | DT_TOP);
// draw min, max X
CString str;
txtRect.left = edge.left;
txtRect.right = edge.right;
str.Format(L"%5.2f", pDoc->m_minX);
m_xyTitleDC.DrawText(str,
txtRect, DT_LEFT | DT_TOP);
str.Format(L"%5.2f", pDoc->m_maxX);
m_xyTitleDC.DrawText(str,
txtRect, DT_RIGHT | DT_TOP);
// draw x title and y values
txtRect.top = edge.top;
txtRect.left = rect.left;
txtRect.right = edge.left;
txtRect.bottom = edge.bottom;
m_xyTitleDC.DrawText(m_xTitle,
txtRect,
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
str.Format(L"%5.2f", pDoc->m_minY);
m_xyTitleDC.DrawText(str,
txtRect, DT_LEFT | DT_BOTTOM | DT_SINGLELINE);
str.Format(L"%5.2f", pDoc->m_maxY);
m_xyTitleDC.DrawText(str,
txtRect, DT_LEFT | DT_TOP | DT_SINGLELINE);
m_xyTitleDC.SelectObject(oldFont);
}
}
void CGraphiteView::DrawGraph(CDC *pDC)
{
CRect rect;
CGraphiteDoc* pDoc = GetDocument();
GetClientRect(rect);
if(m_graphDC.GetSafeHdc() == NULL)
{
// first time
m_graphDC.CreateCompatibleDC(pDC);
m_graphBitmap.CreateCompatibleBitmap(pDC,
rect.Width(), rect.Height());
m_graphDC.SelectObject(&m_graphBitmap);
}
m_graphDC.SetBkColor(m_crBack);
m_graphDC.FillRect(rect, &m_brush);
m_graphDC.BitBlt(0, 0,
rect.Width(), rect.Height(),
&m_xyTitleDC, 0, 0, SRCCOPY);
if(pDoc->validDoc())
{
double x,y;
int prevX, prevY;
bool prevValid = false;
CPen penPlot, *oldPen;
penPlot.CreatePen(PS_SOLID, 0, m_crPlot);
oldPen = m_graphDC.SelectObject(&penPlot);
for(x = pDoc->m_minX; x <= pDoc->m_maxX; x += pDoc->m_deltaX)
{
int px, py;
y = pDoc->f(x);
px = physicalX(x);
py = physicalY(y);
if(px < 0 || py < 0)
{
prevValid = false;
continue;
}
else if(prevValid)
{
m_graphDC.MoveTo(prevX, prevY);
m_graphDC.LineTo(px, py);
prevX = px;
prevY = py;
prevValid = true;
}
else
{
//m_graphDC.MoveTo(px, py);
//m_graphDC.LineTo(px, py);
prevX = px;
prevY = py;
prevValid = true;
}
}
m_graphDC.SelectObject(oldPen);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -