You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
422 lines
12 KiB
C++
422 lines
12 KiB
C++
// XTPChartRadarDiagramView.cpp
|
|
//
|
|
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
|
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
|
//
|
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
|
// CONSENT OF CODEJOCK SOFTWARE.
|
|
//
|
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
|
// SINGLE COMPUTER.
|
|
//
|
|
// CONTACT INFORMATION:
|
|
// support@codejock.com
|
|
// http://www.codejock.com
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include <math.h>
|
|
|
|
#include "../../Types/XTPChartTypes.h"
|
|
#include "Common/Base/Types/XTPPoint3.h"
|
|
|
|
#include "../../XTPChartDefines.h"
|
|
#include "../../XTPChartElement.h"
|
|
#include <Chart/XTPChartLegendItem.h>
|
|
#include "../../XTPChartElementView.h"
|
|
#include "../../XTPChartPanel.h"
|
|
#include <Chart/XTPChartSeriesPointView.h>
|
|
#include "../../XTPChartSeriesView.h"
|
|
#include "../../XTPChartSeries.h"
|
|
#include "../../XTPChartSeriesPoint.h"
|
|
#include "../../XTPChartDiagram.h"
|
|
#include "../../XTPChartDiagramView.h"
|
|
#include "../../XTPChartTitle.h"
|
|
#include "../../XTPChartSeriesStyle.h"
|
|
#include "../../XTPChartSeriesLabel.h"
|
|
|
|
#include "../Axis/XTPChartAxis.h"
|
|
#include "../Axis/XTPChartAxisView.h"
|
|
#include "../Axis/XTPChartRadarAxisView.h"
|
|
#include "../Axis/XTPChartRadarAxisXView.h"
|
|
#include "../Axis/XTPChartRadarAxisYView.h"
|
|
|
|
#include "../../Drawing/XTPChartDeviceCommand.h"
|
|
#include "../../Drawing/XTPChartCircleDeviceCommand.h"
|
|
#include "../../Drawing/XTPChartRectangleDeviceCommand.h"
|
|
#include "../../Drawing/XTPChartTransformationDeviceCommand.h"
|
|
#include "../../Appearance/XTPChartFillStyle.h"
|
|
#include "../../Appearance/XTPChartAppearance.h"
|
|
#include "../../Appearance/XTPChartLineStyle.h"
|
|
#include <Common/XTPMathUtils.h>
|
|
|
|
#include "XTPChartRadarDiagram.h"
|
|
#include "XTPChartRadarDiagramView.h"
|
|
#include "XTPChartRadarDiagramSeriesStyle.h"
|
|
#include "XTPChartRadarDiagramSeriesView.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CXTPChartRadarDiagramView
|
|
|
|
CXTPChartRadarDiagramView::CXTPChartRadarDiagramView(CXTPChartDiagram* pDiagram, CXTPChartElementView* pParent)
|
|
: CXTPChartDiagramView(pDiagram, pParent)
|
|
{
|
|
m_pAxisViews = NULL;
|
|
|
|
m_rcLabelPadding.SetRectEmpty();
|
|
m_rcBounds.SetRectEmpty();
|
|
|
|
m_ptCenter = CXTPPoint2i(0, 0);
|
|
m_nRadius = 0;
|
|
|
|
m_pAxisXView = NULL;
|
|
m_pAxisYView = NULL;
|
|
}
|
|
|
|
CXTPChartRadarAxisView* CXTPChartRadarDiagramView::AddAxisView(CXTPChartDeviceContext* pDC, CXTPChartElementView* pParentView, CXTPChartAxis* pAxis)
|
|
{
|
|
CXTPChartRadarAxisView* pAxisView = (CXTPChartRadarAxisView*)pAxis->CreateView(pDC, pParentView);
|
|
|
|
pAxisView->CreateView(pDC);
|
|
|
|
return pAxisView;
|
|
}
|
|
|
|
CXTPChartRadarAxisView* CXTPChartRadarDiagramView::GetAxisView(CXTPChartAxis* pAxis) const
|
|
{
|
|
for (int i = 0; i < m_pAxisViews->GetCount(); i++)
|
|
{
|
|
CXTPChartRadarAxisView* pAxisView = (CXTPChartRadarAxisView*)m_pAxisViews->GetAt(i);
|
|
|
|
if (pAxisView->GetAxis() == pAxis)
|
|
return pAxisView;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void CXTPChartRadarDiagramView::UpdateRange(CXTPChartDeviceContext* pDC)
|
|
{
|
|
UNREFERENCED_PARAMETER(pDC);
|
|
int i;
|
|
|
|
for (i = 0; i < GetSeriesView()->GetCount(); i++)
|
|
{
|
|
CXTPChartRadarDiagramSeriesView* pSeriesView = (CXTPChartRadarDiagramSeriesView*)GetSeriesView()->GetAt(i);
|
|
|
|
pSeriesView->BeforeUpdateRange(pDC);
|
|
}
|
|
|
|
for (i = 0; i < m_pAxisViews->GetCount(); i++)
|
|
{
|
|
CXTPChartRadarAxisView* pAxisView = (CXTPChartRadarAxisView*)m_pAxisViews->GetAt(i);
|
|
|
|
for (int j = 0; j < GetSeriesView()->GetCount(); j++)
|
|
{
|
|
CXTPChartSeriesView* pSeriesView = (CXTPChartSeriesView*)GetSeriesView()->GetAt(j);
|
|
if (!pSeriesView->GetSeries()->IsVisible())
|
|
continue;
|
|
|
|
CXTPChartRadarDiagramSeriesStyle* pStyle = DYNAMIC_DOWNCAST(CXTPChartRadarDiagramSeriesStyle, pSeriesView->GetSeries()->GetStyle());
|
|
|
|
ASSERT(pStyle);
|
|
if (!pStyle)
|
|
continue;
|
|
|
|
|
|
BOOL bAxisX = !pAxisView->GetAxis()->IsValuesAxis();
|
|
|
|
pAxisView->m_arrSeries.Add(pSeriesView);
|
|
|
|
if (bAxisX)
|
|
((CXTPChartRadarDiagramSeriesView*)pSeriesView)->m_pAxisViewX = pAxisView;
|
|
else
|
|
((CXTPChartRadarDiagramSeriesView*)pSeriesView)->m_pAxisViewY = pAxisView;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < m_pAxisViews->GetCount(); i++)
|
|
{
|
|
CXTPChartRadarAxisView* pAxisView = (CXTPChartRadarAxisView*)m_pAxisViews->GetAt(i);
|
|
|
|
pAxisView->GetAxis()->UpdateRange(pDC, pAxisView);
|
|
|
|
pAxisView->AddLegendItems();
|
|
}
|
|
|
|
for (i = 0; i < GetSeriesView()->GetCount(); i++)
|
|
{
|
|
CXTPChartRadarDiagramSeriesView* pSeriesView = (CXTPChartRadarDiagramSeriesView*)GetSeriesView()->GetAt(i);
|
|
|
|
pSeriesView->AfterUpdateRange(pDC);
|
|
}
|
|
}
|
|
|
|
void CXTPChartRadarDiagramView::CheckLabelBounds(const CXTPChartRectF& rcBounds)
|
|
{
|
|
if (rcBounds.GetTop() < m_rcBounds.top)
|
|
{
|
|
m_rcLabelPadding.top = max(m_rcLabelPadding.top, m_rcBounds.top - (LONG)rcBounds.GetTop());
|
|
}
|
|
|
|
if (rcBounds.GetRight() > m_rcBounds.right)
|
|
{
|
|
m_rcLabelPadding.right = max(m_rcLabelPadding.right, (LONG)rcBounds.GetRight() - m_rcBounds.right);
|
|
}
|
|
|
|
if (rcBounds.GetLeft() < m_rcBounds.left)
|
|
{
|
|
m_rcLabelPadding.left = max(m_rcLabelPadding.left, m_rcBounds.left - (LONG)rcBounds.GetLeft());
|
|
}
|
|
|
|
if (rcBounds.GetBottom() > m_rcBounds.bottom)
|
|
{
|
|
m_rcLabelPadding.bottom = max(m_rcLabelPadding.bottom, (LONG)rcBounds.GetBottom() - m_rcBounds.bottom);
|
|
}
|
|
}
|
|
|
|
void CXTPChartRadarDiagramView::CalculateView(CXTPChartDeviceContext* pDC, CRect rcBounds)
|
|
{
|
|
UNREFERENCED_PARAMETER(pDC);
|
|
UNREFERENCED_PARAMETER(rcBounds);
|
|
m_pDiagram->GetTitles()->CalculateView(pDC, rcBounds, m_pTitlesView);
|
|
|
|
m_rcLabelPadding.SetRectEmpty();
|
|
|
|
CRect rcDiagramBounds = rcBounds;
|
|
|
|
for (int nUpdate = 0; nUpdate < 2; nUpdate++)
|
|
{
|
|
const int AXIS_GAP = 10;
|
|
|
|
rcBounds = rcDiagramBounds;
|
|
rcBounds.DeflateRect(m_rcLabelPadding);
|
|
|
|
rcBounds.DeflateRect(AXIS_GAP, AXIS_GAP);
|
|
|
|
int nSize = min(rcBounds.Width(), rcBounds.Height());
|
|
|
|
m_ptCenter = CXTPPoint2i((rcBounds.right + rcBounds.left) / 2, (rcBounds.top + rcBounds.bottom) / 2);
|
|
m_nRadius = nSize / 2;
|
|
|
|
rcBounds.left = m_ptCenter.X - m_nRadius;
|
|
rcBounds.right = rcBounds.left + m_nRadius * 2;
|
|
|
|
rcBounds.top = m_ptCenter.Y - m_nRadius;
|
|
rcBounds.bottom = rcBounds.top + m_nRadius * 2;
|
|
|
|
m_rcBounds = rcBounds;
|
|
|
|
m_rcLabelPadding.SetRectEmpty();
|
|
|
|
CRect rcPane(rcBounds);
|
|
|
|
int i;
|
|
|
|
CXTPChartRadarDiagram* pDiagram = (CXTPChartRadarDiagram*)GetDiagram();
|
|
|
|
pDiagram->UpdateLayout(pDC, this, rcBounds);
|
|
|
|
|
|
|
|
for (i = 0; i < m_pAxisViews->GetCount(); i++)
|
|
{
|
|
CXTPChartRadarAxisView* pAxisView = (CXTPChartRadarAxisView*)m_pAxisViews->GetAt(i);
|
|
|
|
pAxisView->CalcSize(pDC, rcPane);
|
|
|
|
pAxisView->SetBounds(pDC, rcBounds);
|
|
}
|
|
|
|
|
|
if (m_rcBounds.Width() < 1 || m_rcBounds.Height() < 1)
|
|
break;
|
|
|
|
pDiagram->CalculateSeriesLayout(pDC, this);
|
|
|
|
for (i = 0; i < m_pLabelsView->GetCount(); i++)
|
|
{
|
|
CXTPChartSeriesLabelView* pLabelView = (CXTPChartSeriesLabelView*)m_pLabelsView->GetAt(i);
|
|
|
|
pLabelView->CalculateLayout(pDC);
|
|
}
|
|
|
|
if( m_rcLabelPadding.IsRectNull())
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CXTPChartRadarDiagramView::CreateView(CXTPChartDeviceContext* pDC)
|
|
{
|
|
CXTPChartDiagramView::CreateView(pDC);
|
|
|
|
CXTPChartRadarDiagram* pDiagram = (CXTPChartRadarDiagram*)GetDiagram();
|
|
|
|
m_pSeriesView = new CXTPChartElementView(this);
|
|
|
|
m_pAxisViews = new CXTPChartElementView(this);
|
|
|
|
m_pAxisXView = (CXTPChartRadarAxisXView*)AddAxisView(pDC, m_pAxisViews, pDiagram->GetAxisX());
|
|
|
|
m_pAxisYView = (CXTPChartRadarAxisYView*)AddAxisView(pDC, m_pAxisViews, pDiagram->GetAxisY());
|
|
|
|
m_pLabelsView = new CXTPChartElementView(this);
|
|
}
|
|
|
|
|
|
|
|
|
|
CXTPChartDeviceCommand* CXTPChartRadarDiagramView::CreatePolygonStripDeviceCommand(CXTPChartDeviceContext* /*pDC*/, double dRadiusFrom, double dRadiusTo,
|
|
const CXTPChartColor& color1, const CXTPChartColor& color2, CXTPChartFillStyle* pFillStyle)
|
|
{
|
|
|
|
CXTPChartRadarAxisXView* pAxisXView = GetAxisXView();
|
|
|
|
CXTPChartPoints arrFillPoints;
|
|
CXTPChartPoints arrClipPoints;
|
|
|
|
BOOL bClipPoints = CXTPMathUtils::Compare(dRadiusFrom, 0) != 0;
|
|
|
|
for (int i = 0; i < pAxisXView->m_arrTicks.GetSize(); i++)
|
|
{
|
|
|
|
double dAngle = pAxisXView->ValueToAngle(pAxisXView->m_arrTicks[i].m_dValue);
|
|
|
|
CXTPChartPointF pt(m_ptCenter.X + cos(dAngle) * dRadiusTo, m_ptCenter.Y - sin(dAngle) * dRadiusTo);
|
|
|
|
arrFillPoints.Add(pt);
|
|
|
|
if (bClipPoints)
|
|
{
|
|
pt = CXTPChartPointF(m_ptCenter.X + cos(dAngle) * dRadiusFrom, m_ptCenter.Y - sin(dAngle) * dRadiusFrom);
|
|
|
|
arrClipPoints.Add(pt);
|
|
|
|
}
|
|
}
|
|
|
|
if (arrClipPoints.GetSize() == 0)
|
|
return pFillStyle->CreateDeviceCommand(arrFillPoints, color1, color2);
|
|
else
|
|
{
|
|
CXTPChartDeviceCommand* pCommands = new CXTPChartClipRegionDeviceCommand(arrClipPoints);
|
|
|
|
pCommands->AddChildCommand(pFillStyle->CreateDeviceCommand(arrFillPoints, color1, color2));
|
|
|
|
return pCommands;
|
|
}
|
|
}
|
|
|
|
CXTPChartDeviceCommand* CXTPChartRadarDiagramView::CreatePolygonLineDeviceCommand(CXTPChartDeviceContext* /*pDC*/, double dRadius,
|
|
const CXTPChartColor& color, CXTPChartLineStyle* pLineStyle)
|
|
{
|
|
|
|
CXTPChartRadarAxisXView* pAxisXView = GetAxisXView();
|
|
|
|
CXTPChartPoints arrPoints;
|
|
|
|
|
|
for (int i = 0; i < pAxisXView->m_arrTicks.GetSize(); i++)
|
|
{
|
|
|
|
double dAngle = pAxisXView->ValueToAngle(pAxisXView->m_arrTicks[i].m_dValue);
|
|
|
|
CXTPChartPointF pt(m_ptCenter.X + cos(dAngle) * dRadius, m_ptCenter.Y - sin(dAngle) * dRadius);
|
|
|
|
arrPoints.Add(pt);
|
|
}
|
|
|
|
if (arrPoints.GetSize() == 0)
|
|
return NULL;
|
|
|
|
CXTPChartPointF pt = arrPoints[0];
|
|
arrPoints.Add(pt);
|
|
|
|
return pLineStyle->CreateDeviceCommand(arrPoints, color);
|
|
}
|
|
|
|
|
|
|
|
CXTPChartDeviceCommand* CXTPChartRadarDiagramView::CreateDeviceCommand(CXTPChartDeviceContext* pDC)
|
|
{
|
|
if (m_nRadius <= 1)
|
|
return NULL;
|
|
|
|
CXTPChartDeviceCommand* pCommand = new CXTPChartDeviceCommand();
|
|
|
|
CXTPChartDeviceCommand* pContainer = pCommand->AddChildCommand(new CXTPChartPolygonAntialiasingDeviceCommand(TRUE));
|
|
|
|
CXTPChartRadarDiagram* pDiagram = (CXTPChartRadarDiagram*)GetDiagram();
|
|
|
|
CXTPChartFillStyle* pFillStyle = pDiagram->GetActualFillStyle();
|
|
|
|
if (pDiagram->GetStyle() == xtpChartRadarDiagramCircle)
|
|
{
|
|
pContainer->AddChildCommand(pFillStyle->CreateCircleDeviceCommand(m_ptCenter, m_nRadius,
|
|
pDiagram->GetActualBackgroundColor(), pDiagram->GetActualBackgroundColor2()));
|
|
|
|
pContainer->AddChildCommand(new CXTPChartBoundedCircleDeviceCommand(m_ptCenter, m_nRadius,
|
|
pDiagram->GetActualBorderColor(), 1));
|
|
}
|
|
else
|
|
{
|
|
pContainer->AddChildCommand(CreatePolygonStripDeviceCommand(pDC, 0, m_nRadius,
|
|
pDiagram->GetActualBackgroundColor(), pDiagram->GetActualBackgroundColor2(), pDiagram->GetActualFillStyle()));
|
|
|
|
CXTPChartLineStyle line(pDiagram);
|
|
pContainer->AddChildCommand(CreatePolygonLineDeviceCommand(pDC, m_nRadius, pDiagram->GetActualBorderColor(), &line));
|
|
|
|
}
|
|
|
|
|
|
CXTPChartElementView* pAxisViews = m_pAxisViews;
|
|
int i;
|
|
|
|
for (i = 0; i < pAxisViews->GetCount(); i++)
|
|
{
|
|
CXTPChartRadarAxisView* pAxisView = (CXTPChartRadarAxisView*)pAxisViews->GetAt(i);
|
|
pContainer->AddChildCommand(pAxisView->CreateInterlacedDeviceCommand(pDC));
|
|
}
|
|
|
|
for (i = 0; i < pAxisViews->GetCount(); i++)
|
|
{
|
|
CXTPChartRadarAxisView* pAxisView = (CXTPChartRadarAxisView*)pAxisViews->GetAt(i);
|
|
pContainer->AddChildCommand(pAxisView->CreateStripsDeviceCommand(pDC));
|
|
}
|
|
|
|
for (i = 0; i < pAxisViews->GetCount(); i++)
|
|
{
|
|
CXTPChartRadarAxisView* pAxisView = (CXTPChartRadarAxisView*)pAxisViews->GetAt(i);
|
|
pContainer->AddChildCommand(pAxisView->CreateGridLinesDeviceCommand(pDC));
|
|
}
|
|
|
|
for (i = 0; i < pAxisViews->GetCount(); i++)
|
|
{
|
|
CXTPChartRadarAxisView* pAxisView = (CXTPChartRadarAxisView*)pAxisViews->GetAt(i);
|
|
pContainer->AddChildCommand(pAxisView->CreateConstantLinesDeviceCommand(pDC, TRUE));
|
|
}
|
|
|
|
pCommand->AddChildCommand(CXTPChartDiagramView::CreateDeviceCommand(pDC));
|
|
|
|
for (i = 0; i < pAxisViews->GetCount(); i++)
|
|
{
|
|
CXTPChartRadarAxisView* pAxisView = (CXTPChartRadarAxisView*)pAxisViews->GetAt(i);
|
|
pContainer->AddChildCommand(pAxisView->CreateConstantLinesDeviceCommand(pDC, FALSE));
|
|
}
|
|
|
|
return pCommand;
|
|
}
|
|
|
|
|
|
CXTPChartPointF CXTPChartRadarDiagramView::GetScreenPoint(const CXTPChartSeriesView* /*pView*/, double x, double y) const
|
|
{
|
|
double dAngle = m_pAxisXView->ValueToAngle(x);
|
|
double dRadius = m_pAxisYView->ValueToRadius(y);
|
|
|
|
return CXTPChartPointF(m_ptCenter.X + cos(dAngle) * dRadius, m_ptCenter.Y - sin(dAngle) * dRadius);
|
|
}
|