19#include "../utils/ElementPlotData.h"
22#include <wx/mstream.h>
24ChartView::ChartView(wxWindow* parent, std::vector<ElementPlotData> epdList, std::vector<double> time, PlotLib plotLib)
25 : ChartViewBase(parent)
32 m_menuItemShowGrid->Check(m_hideGrid ?
false : true);
33 m_menuItemShowLabel->Check(m_showLeg);
34 m_menuItemShowCoordinates->Check(m_showCoords);
35 m_menuItemDarkTheme->Check(m_darkTheme);
38 m_pgPropColor = m_pgMgr->Insert(m_pgPropLineProp, 1,
new wxColourProperty(_(
"Color")));
39 m_pgPropColor->SetEditor(wxT(
"ChoiceAndButton"));
40 m_pgPropColor->SetValue(
static_cast<wxVariant
>(
static_cast<wxAny
>(*wxBLACK)));
43 m_pgPropMargins->SetValue(wxT(
"<composed>"));
44 m_pgMgr->Collapse(m_pgPropMargins);
45 m_pgPropAxisLimit->SetValue(wxT(
"<composed>"));
46 m_pgMgr->Collapse(m_pgPropAxisLimit);
49 m_pgProplineType->AddChoice(_(
"Solid"), wxPENSTYLE_SOLID);
50 m_pgProplineType->AddChoice(_(
"Dot"), wxPENSTYLE_DOT);
51 m_pgProplineType->AddChoice(_(
"Dash"), wxPENSTYLE_SHORT_DASH);
52 m_pgProplineType->AddChoice(_(
"Dot and dash"), wxPENSTYLE_DOT_DASH);
53 if (m_plotLib == PlotLib::wxMATH_PLOT) {
54 m_pgProplineType->AddChoice(_(
"Cross"), wxPENSTYLE_CROSS_HATCH);
55 m_pgProplineType->AddChoice(_(
"Driagonal cross"), wxPENSTYLE_CROSSDIAG_HATCH);
58 if (m_plotLib == PlotLib::wxMATH_PLOT) {
60 GetSizer()->Add(m_mpWindow, 1, wxEXPAND, WXC_FROM_DIP(5));
62 else if (m_plotLib == PlotLib::wxCHART_DIR) {
63 m_chartViewerDir =
new wxChartViewer(
this, ID_CHARTVIEWER);
64 m_chartViewerDir->SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
65 m_chartViewerDir->SetMinSize(wxSize(400, 300));
66 m_chartViewerDir->setMouseUsage(Chart::MouseUsageZoomIn);
67 m_chartViewerDir->setSelectionBorderWidth(1);
68 m_chartViewerDir->setSelectionBorderColor(wxColour(0, 125, 255, 255));
69 m_chartViewerDir->setMouseWheelZoomRatio(1.1);
70 m_chartViewerDir->setZoomDirection(Chart::DirectionHorizontalVertical);
71 m_chartViewerDir->setScrollDirection(Chart::DirectionHorizontalVertical);
72 GetSizer()->Add(m_chartViewerDir, 1, wxEXPAND, WXC_FROM_DIP(5));
74 this->Bind(wxEVT_CHARTVIEWER_VIEWPORT_CHANGED, &ChartView::OnViewPortChanged,
this, ID_CHARTVIEWER);
75 this->Bind(wxEVT_CHARTVIEWER_MOUSEMOVE_PLOTAREA, &ChartView::OnMouseMovePlotArea,
this, ID_CHARTVIEWER);
76 m_chartViewerDir->Bind(wxEVT_RIGHT_DOWN, &ChartView::OnRightClickDown,
this);
78 m_pgPropMarginsUp->SetValue(10);
79 m_pgPropMarginsLeft->SetValue(50);
80 m_pgPropMarginsRight->SetValue(40);
81 m_pgPropMarginsBot->SetValue(40);
83 m_pgPropXLabel->SetValue(_(
"auto"));
84 m_pgPropYLabel->SetValue(_(
"auto"));
97ChartView::~ChartView()
99 if (m_plotLib == PlotLib::wxCHART_DIR) {
100 this->Unbind(wxEVT_CHARTVIEWER_VIEWPORT_CHANGED, &ChartView::OnViewPortChanged,
this, ID_CHARTVIEWER);
101 this->Unbind(wxEVT_CHARTVIEWER_MOUSEMOVE_PLOTAREA, &ChartView::OnMouseMovePlotArea,
this, ID_CHARTVIEWER);
102 m_chartViewerDir->Unbind(wxEVT_RIGHT_DOWN, &ChartView::OnRightClickDown,
this);
105void ChartView::SetMPWindow()
107 m_mpWindow =
new mpWindow(
this, wxID_ANY);
109 m_mpWindow->SetDoubleBuffered(
true);
111 m_mpWindow->SetMargins(20, 10, 40, 60);
112 m_xaxis =
new mpScaleX(
"", mpALIGN_BOTTOM,
true);
113 m_yaxis =
new mpScaleY(
"", mpALIGN_LEFT,
true);
114 m_xaxis->SetDrawOutsideMargins(
false);
115 m_yaxis->SetDrawOutsideMargins(
false);
116 m_xaxis->SetTicks(m_hideGrid);
117 m_yaxis->SetTicks(m_hideGrid);
119 m_leg =
new mpInfoLegend(wxRect(200, 20, 40, 40), wxWHITE_BRUSH);
120 m_coords =
new mpInfoCoords(wxRect(0, 0, 0, 0), wxWHITE_BRUSH);
122 m_chartTitle =
new mpText(
"", 50, 0);
123 wxFont chartTitleFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
124 m_chartTitle->SetFont(chartTitleFont);
126 m_mpWindow->AddLayer(m_xaxis);
127 m_mpWindow->AddLayer(m_yaxis);
128 m_mpWindow->AddLayer(m_leg);
129 m_mpWindow->AddLayer(m_coords);
130 m_mpWindow->AddLayer(m_chartTitle);
132 m_leg->SetVisible(m_showLeg);
133 m_coords->SetVisible(m_showCoords);
135 m_mpWindow->EnableDoubleBuffer(
true);
136 m_mpWindow->LockAspect(
false);
140void ChartView::SetTreectrl()
142 wxTreeItemId rootID = m_treeCtrl->AddRoot(wxT(
"root"));
143 m_treeTimeID = m_treeCtrl->AppendItem(rootID, _(
"Time"));
144 m_treeCtrl->SetItemTextColour(m_treeTimeID, *wxRED);
146 bool firstElement[
static_cast<unsigned int>(ElementPlotData::CurveType::NUM_ELEMENTS)];
147 for (
int i = 0; i < static_cast<unsigned int>(ElementPlotData::CurveType::NUM_ELEMENTS); ++i) firstElement[i] =
true;
149 wxString rootElementName[
static_cast<unsigned int>(ElementPlotData::CurveType::NUM_ELEMENTS)];
150 rootElementName[
static_cast<unsigned int>(ElementPlotData::CurveType::CT_BUS)] = _(
"Bus");
151 rootElementName[
static_cast<unsigned int>(ElementPlotData::CurveType::CT_IND_MOTOR)] = _(
"Induction motor");
152 rootElementName[
static_cast<unsigned int>(ElementPlotData::CurveType::CT_LINE)] = _(
"Line");
153 rootElementName[
static_cast<unsigned int>(ElementPlotData::CurveType::CT_LOAD)] = _(
"Load");
154 rootElementName[
static_cast<unsigned int>(ElementPlotData::CurveType::CT_SHUNT_CAPACITOR)] = _(
"Capacitor");
155 rootElementName[
static_cast<unsigned int>(ElementPlotData::CurveType::CT_SHUNT_INDUCTOR)] = _(
"Inductor");
156 rootElementName[
static_cast<unsigned int>(ElementPlotData::CurveType::CT_SYNC_COMPENSATOR)] = _(
"Synchronous compensator");
157 rootElementName[
static_cast<unsigned int>(ElementPlotData::CurveType::CT_SYNC_GENERATOR)] = _(
"Synchronous generator");
158 rootElementName[
static_cast<unsigned int>(ElementPlotData::CurveType::CT_TRANSFORMER)] = _(
"Transformer");
159 rootElementName[
static_cast<unsigned int>(ElementPlotData::CurveType::CT_TEST)] = _(
"Test");
161 wxTreeItemId rootItemID[
static_cast<unsigned int>(ElementPlotData::CurveType::NUM_ELEMENTS)];
163 for (
auto it = m_epdList.begin(), itEnd = m_epdList.end(); it != itEnd; ++it) {
165 unsigned int curveType =
static_cast<unsigned int>(data.GetCurveType());
167 if (firstElement[curveType]) {
168 rootItemID[curveType] = m_treeCtrl->AppendItem(rootID, rootElementName[curveType]);
169 firstElement[curveType] =
false;
171 wxTreeItemId itemID = m_treeCtrl->AppendItem(rootItemID[curveType], data.GetName());
172 for (
int i = 0; i < data.GetElementDataNumber(); ++i) {
173 m_treeCtrl->AppendItem(itemID, data.GetDataName(i), -1, -1, data.GetPlotData(i));
178void ChartView::OnPropertyGridChange(wxPropertyGridEvent& event)
181 wxString pName =
event.GetPropertyName();
182 if (pName.empty())
return;
184 if (m_treeCtrl->GetSelection()) {
185 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(m_treeCtrl->GetSelection()))) {
186 if (pName == _(
"Draw")) {
187 bool isPlotting = m_pgPropDraw->GetValue();
188 data->SetPlot(isPlotting);
190 wxColour colour = GetNextColour();
191 data->SetColour(colour);
192 m_pgPropColor->SetValue(
static_cast<wxVariant
>(
static_cast<wxAny
>(colour)));
193 m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(),
true);
196 m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(),
false);
200 else if (pName == _(
"Color")) {
202 colour << m_pgPropColor->GetValue();
203 data->SetColour(colour);
205 else if (pName == _(
"Thickness")) {
206 data->SetThick(m_pgProplineThick->GetValue().GetInteger());
208 else if (pName == _(
"Type")) {
209 data->SetPenType(
static_cast<wxPenStyle
>(m_pgProplineType->GetValue().GetInteger()));
211 else if (pName == _(
"Axis")) {
212 int axis = m_pgProplineAxis->GetValue().GetInteger();
215 AllToYAxis(m_treeCtrl->GetRootItem());
217 m_treeCtrl->SetItemTextColour(m_treeCtrl->GetSelection(), *wxRED);
218 m_xAxisValues = data->GetValues();
219 m_sugestXLabel = data->GetName() + GetUnitFromMagText(data->GetName());
227 if (pName == _(
"Margins")) {
228 if (m_plotLib == PlotLib::wxMATH_PLOT) {
229 m_mpWindow->SetMargins(m_pgPropMarginsUp->GetValue().GetLong(), m_pgPropMarginsRight->GetValue().GetLong(),
230 m_pgPropMarginsBot->GetValue().GetLong(), m_pgPropMarginsLeft->GetValue().GetLong());
231 m_mpWindow->UpdateAll();
233 else if (m_plotLib == PlotLib::wxCHART_DIR) {
234 m_chartViewerDir->updateViewPort(
true,
false);
238 if (pName == _(
"Axis limit")) {
239 if (m_plotLib == PlotLib::wxMATH_PLOT) {
240 m_mpWindow->Fit(m_pgPropXMin->GetValue().GetDouble(), m_pgPropXMax->GetValue().GetDouble(),
241 m_pgPropYMin->GetValue().GetDouble(), m_pgPropYMax->GetValue().GetDouble());
242 m_mpWindow->UpdateAll();
244 else if (m_plotLib == PlotLib::wxCHART_DIR) {
245 m_forceAxisLimits =
true;
252void ChartView::OnRightClickDown(wxMouseEvent& event)
257void ChartView::OnMenuDarkThemeClick(wxCommandEvent& event)
259 m_darkTheme =
event.IsChecked();
261 if (m_plotLib == PlotLib::wxMATH_PLOT) {
262 wxColour grey(96, 96, 96);
265 m_mpWindow->SetColourTheme(*wxBLACK, *wxWHITE, grey);
266 m_leg->SetBrush(*wxBLACK_BRUSH);
267 m_coords->SetBrush(*wxBLACK_BRUSH);
270 m_mpWindow->SetColourTheme(*wxWHITE, *wxBLACK, grey);
271 m_leg->SetBrush(*wxWHITE_BRUSH);
272 m_coords->SetBrush(*wxWHITE_BRUSH);
275 m_mpWindow->UpdateAll();
277 else if (m_plotLib == PlotLib::wxCHART_DIR) {
282void ChartView::OnMenuSaveImageClick(wxCommandEvent& event)
284 if (m_plotLib == PlotLib::wxMATH_PLOT) {
285 int x = m_mpWindow->GetScreenPosition().x;
286 int y = m_mpWindow->GetScreenPosition().y;
287 int width = m_mpWindow->GetSize().GetWidth();
288 int height = m_mpWindow->GetSize().GetHeight();
291 wxBitmap screenshot(width, height);
294 memDC.SelectObject(screenshot);
296 memDC.Blit(0, 0, width, height, &dcScreen, x, y);
297 memDC.SelectObject(wxNullBitmap);
299 wxFileDialog saveFileDialog(
300 this, _(
"Save image"),
"",
"",
301 "PNG image file (*.png)|*.png|Bitmap image file (*.bmp)|*.bmp|JPEG image file (*.jpg)|*.jpg",
302 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
303 if (saveFileDialog.ShowModal() == wxID_CANCEL)
return;
305 wxFileName imagePath(saveFileDialog.GetPath());
306 wxBitmapType imageType = wxBITMAP_TYPE_BMP;
308 if (imagePath.GetExt() ==
"png")
309 imageType = wxBITMAP_TYPE_PNG;
310 else if (imagePath.GetExt() ==
"jpg")
311 imageType = wxBITMAP_TYPE_JPEG;
313 screenshot.SaveFile(imagePath.GetFullPath(), imageType);
315 else if (m_plotLib == PlotLib::wxCHART_DIR) {
316 wxFileDialog saveFileDialog(
317 this, _(
"Save image"),
"",
"",
318 "PNG (*.png)|*.png|JPG (*.jpg)|*.jpg|GIF (*.gif)|*.gif|BMP (*.bmp)|*.bmp|SVG (*.svg)|*.svg|PDF (*.pdf)|*.pdf",
319 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
320 if (saveFileDialog.ShowModal() == wxID_CANCEL)
return;
322 wxFileName imagePath(saveFileDialog.GetPath());
323 m_chartViewerDir->getChart()->makeChart(imagePath.GetFullPath().ToUTF8());
327void ChartView::OnMenuSendClipClick(wxCommandEvent& event)
330 if (m_plotLib == PlotLib::wxMATH_PLOT) {
331 int x = m_mpWindow->GetScreenPosition().x;
332 int y = m_mpWindow->GetScreenPosition().y;
333 int width = m_mpWindow->GetSize().GetWidth();
334 int height = m_mpWindow->GetSize().GetHeight();
337 screenshot = wxBitmap(width, height);
340 memDC.SelectObject(screenshot);
342 memDC.Blit(0, 0, width, height, &dcScreen, x, y);
343 memDC.SelectObject(wxNullBitmap);
345 else if (m_plotLib == PlotLib::wxCHART_DIR) {
346 MemBlock memBl = m_chartViewerDir->getChart()->makeChart(Chart::BMP);
347 wxMemoryInputStream in(memBl.data, memBl.len);
348 screenshot = wxBitmap(wxImage(in, wxBITMAP_TYPE_BMP));
351 if (screenshot.IsOk()) {
352 if (wxTheClipboard->Open()) {
353 wxTheClipboard->SetData(
new wxBitmapDataObject(screenshot));
354 wxTheClipboard->Close();
356 wxMessageDialog msgDialog(
this, _(
"Chart send to clipboard"), _(
"Info"), wxOK | wxICON_INFORMATION,
358 msgDialog.ShowModal();
361 wxMessageDialog msgDialog(
this, _(
"It was not possible to send to clipboard"), _(
"Error"), wxOK | wxICON_ERROR,
363 msgDialog.ShowModal();
367 wxMessageDialog msgDialog(
this, _(
"It was not possible to create the screenshot"), _(
"Error"), wxOK | wxICON_ERROR,
369 msgDialog.ShowModal();
373void ChartView::OnMenuShowCoordinatesClick(wxCommandEvent& event)
375 m_showCoords =
event.IsChecked();
376 if (m_plotLib == PlotLib::wxMATH_PLOT) {
377 m_coords->SetVisible(m_showCoords);
378 m_mpWindow->UpdateAll();
380 else if (m_plotLib == PlotLib::wxCHART_DIR) {
382 XYChart* chart =
static_cast<XYChart*
>(m_chartViewerDir->getChart());
383 m_trackLinePos = chart->getPlotArea()->getLeftX() + (int)(chart->getPlotArea()->getWidth() * 0.5);
389void ChartView::OnMenuShowGridClick(wxCommandEvent& event)
391 m_hideGrid =
event.IsChecked() ? false :
true;
392 if (m_plotLib == PlotLib::wxMATH_PLOT) {
393 m_xaxis->SetTicks(m_hideGrid);
394 m_yaxis->SetTicks(m_hideGrid);
395 m_mpWindow->UpdateAll();
397 else if (m_plotLib == PlotLib::wxCHART_DIR) {
402void ChartView::OnMenuShowLabelClick(wxCommandEvent& event)
404 m_showLeg =
event.IsChecked();
406 if (m_plotLib == PlotLib::wxMATH_PLOT) {
407 m_leg->SetVisible(m_showLeg);
408 m_mpWindow->UpdateAll();
410 else if (m_plotLib == PlotLib::wxCHART_DIR) {
411 if (!m_showLeg) m_legendHeight = 0;
418 if (m_plotLib == PlotLib::wxMATH_PLOT) {
421 m_mpWindow->GetBoundingBox(bBox);
423 m_pgPropXMin->SetValue(bBox[0]);
424 m_pgPropXMax->SetValue(bBox[1]);
425 m_pgPropYMin->SetValue(bBox[2]);
426 m_pgPropYMax->SetValue(bBox[3]);
428 else if (m_plotLib == PlotLib::wxCHART_DIR) {
429 m_forceAxisLimits =
false;
431 m_chartViewerDir->setFullRange(
"x", 0, 0);
432 m_chartViewerDir->setFullRange(
"y", 0, 0);
433 m_chartViewerDir->setViewPortLeft(0);
434 m_chartViewerDir->setViewPortTop(0);
435 m_chartViewerDir->setViewPortWidth(1);
436 m_chartViewerDir->setViewPortHeight(1);
439 m_chartViewerDir->updateViewPort(
true,
false);
443void ChartView::UpdatePlot(
bool fit)
445 if (m_plotLib == PlotLib::wxMATH_PLOT) {
446 wxRect legRect = m_leg->GetRectangle();
447 wxRect coordsRect = m_coords->GetRectangle();
448 m_mpWindow->DelAllLayers(
true,
false);
451 UpdateAllPlots(m_treeCtrl->GetRootItem());
453 m_xaxis =
new mpScaleX(m_pgPropXLabel->GetValueAsString(), mpALIGN_BOTTOM,
true);
454 m_yaxis =
new mpScaleY(m_pgPropYLabel->GetValueAsString(), mpALIGN_LEFT,
true);
455 m_leg =
new mpInfoLegend(legRect, wxWHITE_BRUSH);
456 m_coords =
new mpInfoCoords(coordsRect, wxWHITE_BRUSH);
458 m_xaxis->SetDrawOutsideMargins(
false);
459 m_yaxis->SetDrawOutsideMargins(
false);
460 m_xaxis->SetTicks(m_hideGrid);
461 m_yaxis->SetTicks(m_hideGrid);
463 mpText* chartTitle =
new mpText(m_pgPropChartTitle->GetValueAsString(), 50, 0);
464 wxFont chartTitleFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
465 chartTitle->SetFont(chartTitleFont);
467 m_mpWindow->AddLayer(m_xaxis);
468 m_mpWindow->AddLayer(m_yaxis);
469 m_mpWindow->AddLayer(m_leg);
470 m_mpWindow->AddLayer(m_coords);
471 m_mpWindow->AddLayer(chartTitle);
473 m_leg->SetVisible(m_showLeg);
474 m_coords->SetVisible(m_showCoords);
478 wxColour grey(96, 96, 96);
480 m_mpWindow->SetColourTheme(*wxBLACK, *wxWHITE, grey);
481 m_leg->SetBrush(*wxBLACK_BRUSH);
482 m_coords->SetBrush(*wxBLACK_BRUSH);
485 m_mpWindow->SetColourTheme(*wxWHITE, *wxBLACK, grey);
486 m_leg->SetBrush(*wxWHITE_BRUSH);
487 m_coords->SetBrush(*wxWHITE_BRUSH);
490 else if (m_plotLib == PlotLib::wxCHART_DIR) {
496void ChartView::OnTreeItemActivated(wxTreeEvent& event)
498 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(event.GetItem()))) {
499 bool isPlotting = data->IsPlot() ? false :
true;
500 data->SetPlot(isPlotting);
501 m_pgPropDraw->SetValue(data->IsPlot());
503 wxColour colour = GetNextColour();
504 data->SetColour(colour);
505 m_pgPropColor->SetValue(
static_cast<wxVariant
>(
static_cast<wxAny
>(colour)));
506 m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(),
true);
509 m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(),
false);
514 if (event.GetItem() == m_treeTimeID) {
515 AllToYAxis(m_treeCtrl->GetRootItem());
516 m_treeCtrl->SetItemTextColour(m_treeTimeID, *wxRED);
517 m_xAxisValues = m_time;
518 m_sugestXLabel = _(
"Time (s)");
525void ChartView::OnTreeItemSelectionChanged(wxTreeEvent& event)
527 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(m_selectedItemID)))
528 data->SetHighlight(
false);
530 m_selectedItemID =
event.GetItem();
532 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(m_selectedItemID))) {
533 m_pgPropDraw->SetValue(data->IsPlot());
535 colour << data->GetColour();
536 m_pgPropColor->SetValue(colour);
537 m_pgProplineThick->SetValue(data->GetThick());
538 m_pgProplineType->SetValue(data->GetPenType());
539 m_pgProplineAxis->SetValue(data->GetAxis());
540 data->SetHighlight(
true);
542 if (m_plotLib == PlotLib::wxCHART_DIR) {
543 m_chartViewerDir->updateViewPort(
true,
false);
548void ChartView::BuildColourList()
550 m_colourList.push_back(wxColour(255, 30, 0));
551 m_colourList.push_back(wxColour(0, 30, 255));
552 m_colourList.push_back(wxColour(0, 128, 0));
553 m_colourList.push_back(wxColour(100, 100, 100));
554 m_colourList.push_back(wxColour(255, 128, 0));
555 m_colourList.push_back(wxColour(128, 0, 255));
556 m_colourList.push_back(wxColour(0, 255, 128));
557 m_colourList.push_back(wxColour(255, 255, 0));
558 m_colourList.push_back(wxColour(255, 0, 255));
559 m_colourList.push_back(wxColour(0, 255, 255));
560 m_colourList.push_back(wxColour(128, 255, 0));
561 m_colourList.push_back(wxColour(255, 0, 128));
562 m_colourList.push_back(wxColour(0, 128, 255));
563 m_colourList.push_back(wxColour(128, 128, 128));
564 m_colourList.push_back(*wxBLACK);
565 m_itColourList = --m_colourList.end();
568wxColour ChartView::GetNextColour()
570 if (*m_itColourList == *wxBLACK)
571 m_itColourList = m_colourList.begin();
575 return *m_itColourList;
578wxTreeItemId ChartView::AllToYAxis(wxTreeItemId root)
580 wxTreeItemIdValue cookie;
581 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
584 while (item.IsOk()) {
585 m_treeCtrl->SetItemTextColour(item, *wxBLACK);
586 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(item))) data->SetAxis(0);
588 if (m_treeCtrl->ItemHasChildren(item)) {
589 wxTreeItemId nextChild = AllToYAxis(item);
590 if (nextChild.IsOk())
return nextChild;
592 item = m_treeCtrl->GetNextChild(root, cookie);
595 wxTreeItemId dummyID;
599wxTreeItemId ChartView::UpdateAllPlots(wxTreeItemId root)
601 wxTreeItemIdValue cookie;
602 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
605 while (item.IsOk()) {
606 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(item))) {
607 if (data->IsPlot()) {
608 wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
609 mpFXYVector* newLayer =
new mpFXYVector(data->GetName() +
" (" + parentName +
")");
610 newLayer->SetData(m_xAxisValues, data->GetValues());
611 newLayer->SetContinuity(
true);
612 wxPen layerPen(data->GetColour(), data->GetThick(), data->GetPenType());
613 newLayer->SetPen(layerPen);
614 newLayer->SetDrawOutsideMargins(
false);
615 newLayer->ShowName(
false);
617 m_mpWindow->AddLayer(newLayer);
621 if (m_treeCtrl->ItemHasChildren(item)) {
622 wxTreeItemId nextChild = UpdateAllPlots(item);
623 if (nextChild.IsOk())
return nextChild;
625 item = m_treeCtrl->GetNextChild(root, cookie);
628 wxTreeItemId dummyID;
632wxTreeItemId ChartView::UpdateAllPlotsCharDir(wxTreeItemId root, XYChart* chartDir)
634 wxTreeItemIdValue cookie;
635 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
638 while (item.IsOk()) {
639 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(item))) {
640 if (data->IsPlot()) {
641 wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
643 std::vector<double> yValues = data->GetValues();
647 LineLayer* layer = chartDir->addLineLayer();
648 layer->setFastLineMode();
649 layer->setLineWidth(data->GetThick());
650 layer->setXData(DoubleArray(&m_xAxisValues[0], m_xAxisValues.size()));
652 if (m_firstPlot) m_rawDataColour.clear();
653 int dataColour = (data->GetColour().Red() << 16) + (data->GetColour().Green() << 8) + data->GetColour().Blue();
654 int rawColour = dataColour;
656 if (data->GetPenType() == wxPENSTYLE_DOT)
657 dataColour = chartDir->dashLineColor(dataColour, Chart::DotLine);
658 else if (data->GetPenType() == wxPENSTYLE_SHORT_DASH)
659 dataColour = chartDir->dashLineColor(dataColour, Chart::DashLine);
660 else if (data->GetPenType() == wxPENSTYLE_DOT_DASH)
661 dataColour = chartDir->dashLineColor(dataColour, Chart::DotDashLine);
662 m_rawDataColour[dataColour] = rawColour;
664 layer->addDataSet(DoubleArray(&yValues[0], yValues.size()), dataColour, data->GetName() +
" (" + parentName +
")");
666 if (data->IsHighlighted()) {
667 int hlColor = 0x80FFFF00;
668 LineLayer* hlLayer = chartDir->addLineLayer();
669 hlLayer->setFastLineMode();
670 hlLayer->setLineWidth(data->GetThick() * 3);
671 hlLayer->setXData(DoubleArray(&m_xAxisValues[0], m_xAxisValues.size()));
672 hlLayer->addDataSet(DoubleArray(&yValues[0], yValues.size()), hlColor);
677 m_sugestYLabel = data->GetName();
680 if (m_sugestYLabel.IsEmpty() || (m_sugestYLabel != data->GetName())) m_sugestYLabel =
"";
685 if (m_treeCtrl->ItemHasChildren(item)) {
686 wxTreeItemId nextChild = UpdateAllPlotsCharDir(item, chartDir);
687 if (nextChild.IsOk())
return nextChild;
689 item = m_treeCtrl->GetNextChild(root, cookie);
693 wxTreeItemId dummyID;
697void ChartView::OnMenuExpCSVClick(wxCommandEvent& event)
699 wxFileDialog saveFileDialog(
this, _(
"Save CSV file"),
"",
"",
"CSV file (*.csv)|*.csv",
700 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
701 if (saveFileDialog.ShowModal() == wxID_CANCEL)
return;
703 wxTextFile csvFile(saveFileDialog.GetPath());
704 if (!csvFile.Create()) {
705 if (!csvFile.Open()) {
706 wxMessageDialog msgDialog(
this, _(
"It was not possible to open or create the selected file."), _(
"Error"),
707 wxOK | wxCENTRE | wxICON_ERROR);
708 msgDialog.ShowModal();
713 if (csvFile.IsOpened()) {
715 csvFile.AddLine(GetActiveCurvesCSV());
721wxString ChartView::GetActiveCurvesCSV()
723 std::vector<PlotData*> activePlotDataList;
724 GetActivePlotData(m_treeCtrl->GetRootItem(), activePlotDataList);
726 std::vector<double> xValues;
730 bool foundXAxis =
false;
731 for (
auto it = activePlotDataList.begin(), itEnd = activePlotDataList.end(); it != itEnd; ++it) {
733 if (data->GetAxis() == 1) {
734 xValues = data->GetValues();
735 xName = data->GetName();
737 activePlotDataList.erase(it);
748 wxString csvText = xName +
";";
750 for (
auto it = activePlotDataList.begin(), itEnd = activePlotDataList.end(); it != itEnd; ++it) {
752 csvText += data->GetName() +
";";
754 csvText[csvText.length() - 1] =
'\n';
756 for (
unsigned int i = 0; i < xValues.size(); ++i) {
757 csvText += wxString::FromCDouble(xValues[i], 13) +
";";
758 for (
unsigned int j = 0; j < activePlotDataList.size(); ++j) {
760 if (i < activePlotDataList[j]->GetValues().size()) {
761 value = activePlotDataList[j]->GetValues()[i];
763 csvText += wxString::FromCDouble(value, 13) +
";";
765 csvText[csvText.length() - 1] =
'\n';
769 for (
auto it = activePlotDataList.begin(); it != activePlotDataList.end(); ++it) {
772 activePlotDataList.clear();
777wxTreeItemId ChartView::GetActivePlotData(wxTreeItemId root, std::vector<PlotData*>& plotDataList)
779 wxTreeItemIdValue cookie;
780 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
783 while (item.IsOk()) {
784 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(item))) {
785 if (data->IsPlot() || data->GetAxis() == 1) {
786 wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
790 dataCopy->SetName(data->GetName() +
" (" + parentName +
")");
791 plotDataList.push_back(dataCopy);
795 if (m_treeCtrl->ItemHasChildren(item)) {
796 wxTreeItemId nextChild = GetActivePlotData(item, plotDataList);
797 if (nextChild.IsOk())
return nextChild;
799 item = m_treeCtrl->GetNextChild(root, cookie);
802 wxTreeItemId dummyID;
805void ChartView::DrawChartDir()
807 int gridColour = 0xEAEAEA;
808 int bgColour = 0xFFFFFF;
809 int labelColour = 0x000000;
812 gridColour = 0x3D3D3D;
813 labelColour = 0xA0A0A0;
815 if (m_hideGrid) gridColour = Chart::Transparent;
817 XYChart* chartDir =
new XYChart(std::max(400, m_chartViewerSize.GetWidth()), std::max(300, m_chartViewerSize.GetHeight()), bgColour);
819 wxString title = m_pgPropChartTitle->GetValueAsString();
821 if (!title.IsEmpty()) {
822 chartDir->addTitle(title,
"arial.ttf", 12, labelColour);
826 LegendBox* box =
nullptr;
828 box = chartDir->addLegend(0, 0,
false,
"arial.ttf", 10);
829 box->setBackground(Chart::Transparent, Chart::Transparent);
830 box->setPos(m_pgPropMarginsLeft->GetValue().GetLong(), m_pgPropMarginsUp->GetValue().GetLong() + titleSize);
831 box->setFontColor(labelColour);
832 box->setLineStyleKey();
835 CalcXYLimits(m_treeCtrl->GetRootItem(), chartDir);
837 UpdateAllPlotsCharDir(m_treeCtrl->GetRootItem(), chartDir);
840 wxString xLabel = m_pgPropXLabel->GetValueAsString();
841 if (xLabel == _(
"auto")) xLabel = m_sugestXLabel;
842 wxString yLabel = m_pgPropYLabel->GetValueAsString();
843 if (yLabel == _(
"auto")) yLabel = m_sugestYLabel + GetUnitFromMagText(m_sugestYLabel);
844 int xLabelSize = 10, yLabelSize = 10;
846 if (xLabel.IsEmpty()) xLabelSize = 0;
847 if (yLabel.IsEmpty()) yLabelSize = 0;
849 chartDir->setPlotArea(
850 yLabelSize + m_pgPropMarginsLeft->GetValue().GetLong(),
851 titleSize + m_legendHeight + m_pgPropMarginsUp->GetValue().GetLong(),
852 chartDir->getWidth() - m_pgPropMarginsRight->GetValue().GetLong() - m_pgPropMarginsLeft->GetValue().GetLong() - yLabelSize,
853 chartDir->getHeight() - m_pgPropMarginsBot->GetValue().GetLong() - m_pgPropMarginsUp->GetValue().GetLong() - m_legendHeight - titleSize - xLabelSize,
854 bgColour, -1, -1, gridColour, gridColour);
855 chartDir->setClipping();
858 double xMin = 0, xMax = 0, yMin = 0, yMax = 0;
859 if (m_forceAxisLimits) {
860 xMin = m_pgPropXMin->GetValue().GetDouble();
861 xMax = m_pgPropXMax->GetValue().GetDouble();
862 yMin = m_pgPropYMin->GetValue().GetDouble();
863 yMax = m_pgPropYMax->GetValue().GetDouble();
871 yMin = m_yMin - 0.05 * (m_yMax - m_yMin);
872 yMax = m_yMax + 0.05 * (m_yMax - m_yMin);
873 m_pgPropXMin->SetValue(xMin);
874 m_pgPropXMax->SetValue(xMax);
875 m_pgPropYMin->SetValue(yMin);
876 m_pgPropYMax->SetValue(yMax);
878 m_chartViewerDir->setFullRange(
"x", xMin, xMax);
879 m_chartViewerDir->setFullRange(
"y", yMin, yMax);
882 double viewPortStartTime = m_chartViewerDir->getValueAtViewPort(
"x", m_chartViewerDir->getViewPortLeft());
883 double viewPortEndTime = m_chartViewerDir->getValueAtViewPort(
"x", m_chartViewerDir->getViewPortLeft() + m_chartViewerDir->getViewPortWidth());
885 chartDir->xAxis()->setTickDensity(20);
886 chartDir->xAxis()->setLinearScale(viewPortStartTime, viewPortEndTime);
887 chartDir->xAxis()->setLabelFormat(wxString::Format(
"{value|2~%c}", DotOrComma()));
888 chartDir->xAxis()->setColors(labelColour, labelColour);
889 chartDir->xAxis()->setTitle(xLabel,
"arial.ttf", 10, labelColour);
891 chartDir->yAxis()->setLabelFormat(wxString::Format(
"{value|2~%c}", DotOrComma()));
892 chartDir->yAxis()->setColors(labelColour, labelColour);
893 chartDir->yAxis()->setTitle(yLabel,
"arial.ttf", 10, labelColour);
894 m_chartViewerDir->syncLinearAxisWithViewPort(
"y", chartDir->yAxis());
897 DrawTrackLine(chartDir);
900 if (m_chartViewerDir->getChart() !=
nullptr)
902 delete m_chartViewerDir->getChart();
905 m_chartViewerDir->setChart(chartDir);
907 if (m_showLeg && box !=
nullptr) {
908 if (std::abs(m_legendHeight - box->getHeight()) > 1) {
909 m_legendHeight = box->getHeight();
915void ChartView::OnViewPortChanged(wxCommandEvent& event)
917 if (m_chartViewerDir->needUpdateChart()) DrawChartDir();
921void ChartView::OnMouseMovePlotArea(wxCommandEvent& event)
924 const int grabDist = 8;
926 int mouseX = m_chartViewerDir->getChartMouseX();
927 PlotArea* plotArea =
static_cast<XYChart*
>(m_chartViewerDir->getChart())->getPlotArea();
930 bool moveTrackLine =
false;
932 if (m_chartViewerDir->getMouseUsage() == Chart::MouseUsageDefault && wxGetMouseState().LeftIsDown()) {
934 SetCursor(wxCURSOR_SIZEWE);
935 moveTrackLine =
true;
938 if (std::abs(mouseX - m_trackLinePos) <= grabDist && !m_chartViewerDir->IsSelectionRectVisible()) {
939 SetCursor(wxCURSOR_SIZEWE);
940 m_chartViewerDir->setMouseUsage(Chart::MouseUsageDefault);
942 else if (!wxGetMouseState().LeftIsDown()) {
943 SetCursor(wxCURSOR_ARROW);
944 m_chartViewerDir->setMouseUsage(Chart::MouseUsageZoomIn);
948 m_trackLinePos = mouseX;
949 DrawTrackLine(
static_cast<XYChart*
>(m_chartViewerDir->getChart()));
950 m_chartViewerDir->updateDisplay();
957void ChartView::DrawTrackLine(XYChart* chartDir)
959 chartDir->initDynamicLayer();
961 double xValue = chartDir->getNearestXValue(m_trackLinePos);
962 int xCoor = chartDir->getXCoor(xValue);
963 chartDir->getDrawArea()->line(xCoor, chartDir->getPlotArea()->getTopY(), xCoor, chartDir->getPlotArea()->getBottomY(), 0x888888, 3);
965 std::ostringstream xlabel;
968 xlabel <<
"<*font,bgColor=000000*> " << chartDir->formatValue(xValue, wxString::Format(
"{value|P4~%c}", DotOrComma())) <<
" <*/font*>";
969 TTFText* text = chartDir->getDrawArea()->text(xlabel.str().c_str(),
"arialbd.ttf", 10);
970 int xLabelPos = std::max(0, std::min(xCoor - text->getWidth() / 2, chartDir->getWidth() - text->getWidth()));
971 text->draw(xLabelPos, chartDir->getPlotArea()->getBottomY() + 3, 0xffffff);
974 for (
int i = 0; i < chartDir->getLayerCount(); ++i)
976 Layer* layer = chartDir->getLayerByZ(i);
979 int xIndex = layer->getXIndexOf(xValue);
982 for (
int j = 0; j < layer->getDataSetCount(); ++j)
984 DataSet* dataSet = layer->getDataSetByZ(j);
985 const char* dataSetName = dataSet->getDataName();
988 int color = dataSet->getDataColor();
989 int yCoor = chartDir->getYCoor(dataSet->getPosition(xIndex), dataSet->getUseYAxis());
992 if ((yCoor >= chartDir->getPlotArea()->getTopY()) && (yCoor <= chartDir->getPlotArea()->getBottomY()) &&
993 (color != Chart::Transparent) && dataSetName && *dataSetName)
995 chartDir->getDrawArea()->circle(xCoor, yCoor, 4, 4, color, color);
997 std::ostringstream label;
1000 label <<
"<*font,bgColor=" << std::hex << m_rawDataColour[color] <<
"*> " << chartDir->formatValue(dataSet->getValue(xIndex), wxString::Format(
"{value|P4~%c}", DotOrComma())) <<
" <*font*>";
1001 text = chartDir->getDrawArea()->text(label.str().c_str(),
"arialbd.ttf", 10);
1006 if (xCoor <= (chartDir->getPlotArea()->getLeftX() + chartDir->getPlotArea()->getRightX()) / 2)
1008 text->draw(xCoor + 6, yCoor, 0xffffff, Chart::Left);
1012 text->draw(xCoor - 6, yCoor, 0xffffff, Chart::Right);
1020wxString ChartView::GetUnitFromMagText(wxString magText)
1022 wxString unitText =
" (p.u.)";
1023 if (magText.IsEmpty()) unitText =
"";
1024 else if (magText == _(
"Angle")) unitText =
" (°)";
1025 else if (magText == _(
"Delta")) unitText =
" (°)";
1026 else if (magText == _(
"Frequency")) unitText =
" (Hz)";
1027 else if (magText == _(
"Velocity")) unitText =
" (rad/s)";
1028 else if (magText == _(
"Slip")) unitText =
" (%)";
1032wxTreeItemId ChartView::CalcXYLimits(wxTreeItemId root, XYChart* chartDir)
1034 wxTreeItemIdValue cookie;
1035 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
1038 while (item.IsOk()) {
1039 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(item))) {
1040 if (data->IsPlot()) {
1041 wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
1043 std::vector<double> yValues = data->GetValues();
1044 if (yValues.size() == 0) {
1045 item = m_treeCtrl->GetNextChild(root, cookie);
1049 double minY = *std::min_element(yValues.begin(), yValues.end());
1050 double maxY = *std::max_element(yValues.begin(), yValues.end());
1052 m_firstPlot =
false;
1056 m_xMin = *std::min_element(m_xAxisValues.begin(), m_xAxisValues.end());
1057 m_xMax = *std::max_element(m_xAxisValues.begin(), m_xAxisValues.end());
1060 if (minY < m_yMin) m_yMin = minY;
1061 if (maxY > m_yMax) m_yMax = maxY;
1066 if (m_treeCtrl->ItemHasChildren(item)) {
1067 wxTreeItemId nextChild = CalcXYLimits(item, chartDir);
1068 if (nextChild.IsOk())
return nextChild;
1070 item = m_treeCtrl->GetNextChild(root, cookie);
1073 wxTreeItemId dummyID;
1077void ChartView::OnResize(wxSizeEvent& event)
1079 if (m_plotLib == PlotLib::wxCHART_DIR) {
1080 m_chartViewerSize =
event.GetSize() - wxSize(m_treeCtrl->GetSize().GetWidth(), 60);
1082 m_chartViewerDir->updateViewPort(
true,
false);
This class is responsible to manage the graphical data of electromechanical result to be plotted on c...