📄 viewtsgraph.cpp
字号:
//////////////////////////////////////////////////////
//
// NRDB Pro - Spatial database and mapping application
//
// Copyright (c) 1989-2004 Richard D. Alexander
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// NRDB Pro is part of the Natural Resources Database Project
//
// Homepage: http://www.nrdb.co.uk/
// Users' Forum: http://nrdb.mypalawan.info/
//
#include "stdafx.h"
#include <strstrea.h>
#include "nrdb.h"
#include "ViewTSGraph.h"
#include "mainfrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
const int MAX_DAYS_MONTH = 31;
const int MAX_STEP = 16;
const double AVERAGE_MONTH=30.4375;
const int MAX_DAYS_YEAR = 366;
/////////////////////////////////////////////////////////////////////////////
// CViewTSGraph
IMPLEMENT_DYNCREATE(CViewTSGraph, CViewGraph)
CViewTSGraph::CViewTSGraph()
{
}
CViewTSGraph::~CViewTSGraph()
{
}
BEGIN_MESSAGE_MAP(CViewTSGraph, CViewGraph)
//{{AFX_MSG_MAP(CViewTSGraph)
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CViewTSGraph drawing
void CViewTSGraph::OnDraw(CDC* pDC)
{
CViewGraph::OnDraw(pDC);
}
/////////////////////////////////////////////////////////////////////////////
// CViewTSGraph diagnostics
#ifdef _DEBUG
void CViewTSGraph::AssertValid() const
{
CViewGraph::AssertValid();
}
void CViewTSGraph::Dump(CDumpContext& dc) const
{
CViewGraph::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
void CViewTSGraph::OnInitialUpdate()
{
CViewGraph::OnInitialUpdate();
// Determine whether to display sticks or lines
for (int iLine = 0; iLine < m_pDoc->GetNumLines(); iLine++)
{
m_prop.m_aGraphStyle[iLine] = CGraphProperties::lines;
if (m_pDoc->GetLegend(iLine).Find(BDString(IDS_TOTAL)) >=0 ) m_prop.m_aGraphStyle[iLine] = CGraphProperties::sticks;
};
}
/////////////////////////////////////////////////////////////////////////////
// CViewTSGraph message handlers
void CViewTSGraph::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
double dValue;
CDateTime datetime;
BeginWaitCursor();
// Retrieve document
m_aXPosData.SetSize(m_pDoc->GetNumLines());
m_aGraphData.SetSize(m_pDoc->GetNumLines());
for (int iLine = 0; iLine < m_pDoc->GetNumLines(); iLine++)
{
BOOL bFound = GetDoc()->GetFirstData(iLine, datetime, dValue);
if (!m_dtStart.IsValid() && datetime.IsValid())
{
m_dtStart = datetime;
m_dtEnd = datetime;
};
while (bFound)
{
// Transfer the data
if (datetime.IsValid())
{
if (datetime < m_dtStart) m_dtStart = datetime;
if (datetime > m_dtEnd) m_dtEnd = datetime;
if (dValue != AFX_RFX_DOUBLE_PSEUDO_NULL)
{
// If monthly or annual data then set to middle
if (datetime.GetMonth() == 0) datetime.Advance(182,0);
else if (datetime.GetDay() == 0) datetime.Advance(15,0);
m_bData = TRUE;
m_aXPosData[iLine].Add(datetime.GetDateLong());
m_aGraphData[iLine].Add(dValue);
}
};
// Get the next reading
bFound = GetDoc()->GetNextData(iLine, datetime, dValue);
}
// Set number of data sets
m_prop.m_aLegendText.SetAtGrow(iLine,m_pDoc->GetLegend(iLine));
m_prop.m_aColour.SetAtGrow(iLine, GetColour(iLine));
m_prop.m_aLineStyle.SetAtGrow(iLine, PS_SOLID);
m_prop.m_aLineWidth.SetAtGrow(iLine, 2);
m_prop.m_aGraphStyle.SetAtGrow(iLine, CGraphProperties::lines);
// For 'total' data such as rainfall, display sticks
};
// Update start and end dates
if (m_dtStart == m_dtEnd)
{
m_dtStart = m_dtStart - 365*5;
m_dtEnd = m_dtEnd + 365*5;
}
// If monthly data then set the last date to the end of the month
if (m_dtEnd.GetMonth() == 0)
{
m_dtEnd.AdvanceYear();
m_dtEnd.Advance(0,-1);
}
else if (m_dtEnd.GetDay() == 0)
{
m_dtEnd.AdvanceMonth();
m_dtEnd.Advance(0,-1);
}
// Update the displacement data
for (iLine = 0; iLine < m_pDoc->GetNumLines(); iLine++)
{
for (int i = 0; i < m_aXPosData[iLine].GetSize(); i++)
{
double dDisp = CDateTime((long)m_aXPosData[iLine][i],0) - m_dtStart;
m_aXPosData[iLine][i] = dDisp;
};
};
m_prop.m_dXMin = 0;
m_prop.m_dXMax = m_dtEnd - m_dtStart;
// Set titles
m_prop.m_sTitle = m_pDoc->GetTitle();
EndWaitCursor();
}
///////////////////////////////////////////////////////////////////////////////
void CViewTSGraph::DrawGraph(CDC* pDC)
{
double dXOld = 0;
double dYOld = 0;
double dX, dY, dY0;
// Draw the data on the graph
for (int i = 0; i < m_aGraphData.GetSize(); i++)
{
// Create pen
int nWidth = GetWidth(pDC, m_prop.m_aLineStyle[i], m_prop.m_aLineWidth[i]);
CPen pen(m_prop.m_aLineStyle[i], nWidth, m_prop.m_aColour[i]);
CPen* pPenOld = pDC->SelectObject(&pen);
// Draw lines
for (int j = 0; j < m_aGraphData[i].GetSize(); j++)
{
dX = m_rectAxis.left + 1 + (m_aXPosData[i][j] - m_prop.m_dXMin) *
(m_rectAxis.Width()-2) / (m_prop.m_dXMax - m_prop.m_dXMin);
dY = m_rectAxis.bottom +1 - (m_aGraphData[i][j] - m_prop.m_dYMin) *
(m_rectAxis.Height()-2) / (m_prop.m_dYMax - m_prop.m_dYMin);
// Join lines
if (m_prop.m_aGraphStyle[i] == CGraphProperties::lines)
{
if (j > 0)
{
pDC->MoveTo((int)dXOld, (int)dYOld);
pDC->LineTo((int)dX,(int)dY);
};
// If only one point then draw a cross
if (m_aGraphData[i].GetSize() == 1)
{
pDC->MoveTo((int)dX - nWidth, (int)dY - nWidth);
pDC->LineTo((int)dX + nWidth, (int)dY + nWidth);
pDC->MoveTo((int)dX - nWidth, (int)dY + nWidth);
pDC->LineTo((int)dX + nWidth, (int)dY - nWidth);
}
}
// Draw sticks
else if (m_prop.m_aGraphStyle[i] == CGraphProperties::sticks)
{
dY0 = m_rectAxis.bottom - (0 - m_prop.m_dYMin) *
(m_rectAxis.Height()) / (m_prop.m_dYMax - m_prop.m_dYMin);
dY0 = max(dY0, m_rectAxis.top);
dY0 = min(dY0, m_rectAxis.bottom);
pDC->MoveTo((int)dX, (int)dY);
pDC->LineTo((int)dX, (int)dY0);
}
else if (m_prop.m_aGraphStyle[i] == CGraphProperties::symbols)
{
int nX = (int)dX;
int nY = (int)dY;
pDC->MoveTo(nX-nWidth, nY-nWidth);
pDC->LineTo(nX+nWidth, nY+nWidth);
pDC->MoveTo(nX-nWidth, nY+nWidth);
pDC->LineTo(nX+nWidth, nY-nWidth);
}
dXOld = dX;
dYOld = dY;
}
pDC->SelectObject(pPenOld);
};
}
///////////////////////////////////////////////////////////////////////////////
//
// BOOL CViewTSGraph::DrawXAxis()
//
void CViewTSGraph::DrawXAxis(CDC* pDC)
{
BOOL bOK = TRUE;
BOOL m_bYearTicks;
CFont font;
CreateFont(pDC, font, 9);
CFont* pFontOld = pDC->SelectObject(&font);
CSize sz = pDC->GetTextExtent("ABC");
m_bDays = FALSE;
m_bMonthsFull = FALSE;
m_bMonths = FALSE;
m_bDecades = FALSE;
// Check that the data represents a valid range
if (!m_dtStart.IsValid()) return;
// Determine position of axis
m_dTextHeight = sz.cy;
m_dTextWidth = sz.cx/3;
m_dOriginX = m_rectAxis.left;
m_dOriginY = m_rectAxis.bottom;
m_dLenX = m_rectAxis.Width();
m_dTickLength = m_dTextHeight / 3;
// Determine positioning of labels
m_dDayY = m_dOriginY + m_dTextHeight*0.2;
m_dMonthY = m_dOriginY + m_dTextHeight*1.0;
m_dYearY = m_dOriginY + m_dTextHeight*1.8;
// Retrieve details of the graph from the corresponding document
m_dRange = m_dtEnd-m_dtStart+1;
// If x scale is negative, do not display as it is not possible to determine where
// graphics server places y axis
if (m_prop.m_dXMin < 0)
{
return;
}
// Determine whether days are shown
if (m_dRange < 100)
{
m_bDays = TRUE;
};
// Determine if there is enough space to draw months in full
if ((m_dTextWidth * 4.0 * m_dRange) / MAX_DAYS_MONTH < m_dLenX)
{
m_bMonthsFull = TRUE;
};
if (m_dRange < 2000)
{
m_bMonths = TRUE;
}
m_bYearTicks = m_dRange < 50000;
if (m_dRange > 10000)
{
m_bDecades = TRUE;
}
// Draw axis ticks for days
if (bOK && m_bDays)
{
CDateTime datetime = m_dtStart;
while (datetime <= m_dtEnd)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -