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)
529 if (m_selectedItemID.IsOk()) {
530 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(m_selectedItemID))) {
531 data->SetHighlight(
false);
535 m_selectedItemID =
event.GetItem();
537 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(m_selectedItemID))) {
538 m_pgPropDraw->SetValue(data->IsPlot());
540 colour << data->GetColour();
541 m_pgPropColor->SetValue(colour);
542 m_pgProplineThick->SetValue(data->GetThick());
543 m_pgProplineType->SetValue(data->GetPenType());
544 m_pgProplineAxis->SetValue(data->GetAxis());
545 data->SetHighlight(
true);
547 if (m_plotLib == PlotLib::wxCHART_DIR) {
548 m_chartViewerDir->updateViewPort(
true,
false);
553void ChartView::BuildColourList()
555 m_colourList.push_back(wxColour(255, 30, 0));
556 m_colourList.push_back(wxColour(0, 30, 255));
557 m_colourList.push_back(wxColour(0, 128, 0));
558 m_colourList.push_back(wxColour(100, 100, 100));
559 m_colourList.push_back(wxColour(255, 128, 0));
560 m_colourList.push_back(wxColour(128, 0, 255));
561 m_colourList.push_back(wxColour(0, 255, 128));
562 m_colourList.push_back(wxColour(255, 255, 0));
563 m_colourList.push_back(wxColour(255, 0, 255));
564 m_colourList.push_back(wxColour(0, 255, 255));
565 m_colourList.push_back(wxColour(128, 255, 0));
566 m_colourList.push_back(wxColour(255, 0, 128));
567 m_colourList.push_back(wxColour(0, 128, 255));
568 m_colourList.push_back(wxColour(128, 128, 128));
569 m_colourList.push_back(*wxBLACK);
570 m_itColourList = --m_colourList.end();
573wxColour ChartView::GetNextColour()
575 if (*m_itColourList == *wxBLACK)
576 m_itColourList = m_colourList.begin();
580 return *m_itColourList;
583wxTreeItemId ChartView::AllToYAxis(wxTreeItemId root)
585 wxTreeItemIdValue cookie;
586 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
589 while (item.IsOk()) {
590 m_treeCtrl->SetItemTextColour(item, *wxBLACK);
591 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(item))) data->SetAxis(0);
593 if (m_treeCtrl->ItemHasChildren(item)) {
594 wxTreeItemId nextChild = AllToYAxis(item);
595 if (nextChild.IsOk())
return nextChild;
597 item = m_treeCtrl->GetNextChild(root, cookie);
600 wxTreeItemId dummyID;
604wxTreeItemId ChartView::UpdateAllPlots(wxTreeItemId root)
606 wxTreeItemIdValue cookie;
607 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
610 while (item.IsOk()) {
611 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(item))) {
612 if (data->IsPlot()) {
613 wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
614 mpFXYVector* newLayer =
new mpFXYVector(data->GetName() +
" (" + parentName +
")");
615 newLayer->SetData(m_xAxisValues, data->GetValues());
616 newLayer->SetContinuity(
true);
617 wxPen layerPen(data->GetColour(), data->GetThick(), data->GetPenType());
618 newLayer->SetPen(layerPen);
619 newLayer->SetDrawOutsideMargins(
false);
620 newLayer->ShowName(
false);
622 m_mpWindow->AddLayer(newLayer);
626 if (m_treeCtrl->ItemHasChildren(item)) {
627 wxTreeItemId nextChild = UpdateAllPlots(item);
628 if (nextChild.IsOk())
return nextChild;
630 item = m_treeCtrl->GetNextChild(root, cookie);
633 wxTreeItemId dummyID;
637wxTreeItemId ChartView::UpdateAllPlotsCharDir(wxTreeItemId root, XYChart* chartDir)
639 wxTreeItemIdValue cookie;
640 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
643 while (item.IsOk()) {
644 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(item))) {
645 if (data->IsPlot()) {
646 wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
648 std::vector<double> yValues = data->GetValues();
652 LineLayer* layer = chartDir->addLineLayer();
653 layer->setFastLineMode();
654 layer->setLineWidth(data->GetThick());
655 layer->setXData(DoubleArray(&m_xAxisValues[0], m_xAxisValues.size()));
657 if (m_firstPlot) m_rawDataColour.clear();
658 int dataColour = (data->GetColour().Red() << 16) + (data->GetColour().Green() << 8) + data->GetColour().Blue();
659 int rawColour = dataColour;
661 if (data->GetPenType() == wxPENSTYLE_DOT)
662 dataColour = chartDir->dashLineColor(dataColour, Chart::DotLine);
663 else if (data->GetPenType() == wxPENSTYLE_SHORT_DASH)
664 dataColour = chartDir->dashLineColor(dataColour, Chart::DashLine);
665 else if (data->GetPenType() == wxPENSTYLE_DOT_DASH)
666 dataColour = chartDir->dashLineColor(dataColour, Chart::DotDashLine);
667 m_rawDataColour[dataColour] = rawColour;
669 layer->addDataSet(DoubleArray(&yValues[0], yValues.size()), dataColour, data->GetName() +
" (" + parentName +
")");
671 if (data->IsHighlighted()) {
672 int hlColor = 0x80FFFF00;
673 LineLayer* hlLayer = chartDir->addLineLayer();
674 hlLayer->setFastLineMode();
675 hlLayer->setLineWidth(data->GetThick() * 3);
676 hlLayer->setXData(DoubleArray(&m_xAxisValues[0], m_xAxisValues.size()));
677 hlLayer->addDataSet(DoubleArray(&yValues[0], yValues.size()), hlColor);
682 m_sugestYLabel = data->GetName();
685 if (m_sugestYLabel.IsEmpty() || (m_sugestYLabel != data->GetName())) m_sugestYLabel =
"";
690 if (m_treeCtrl->ItemHasChildren(item)) {
691 wxTreeItemId nextChild = UpdateAllPlotsCharDir(item, chartDir);
692 if (nextChild.IsOk())
return nextChild;
694 item = m_treeCtrl->GetNextChild(root, cookie);
698 wxTreeItemId dummyID;
702void ChartView::OnMenuExpCSVClick(wxCommandEvent& event)
704 wxFileDialog saveFileDialog(
this, _(
"Save CSV file"),
"",
"",
"CSV file (*.csv)|*.csv",
705 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
706 if (saveFileDialog.ShowModal() == wxID_CANCEL)
return;
708 wxTextFile csvFile(saveFileDialog.GetPath());
709 if (!csvFile.Create()) {
710 if (!csvFile.Open()) {
711 wxMessageDialog msgDialog(
this, _(
"It was not possible to open or create the selected file."), _(
"Error"),
712 wxOK | wxCENTRE | wxICON_ERROR);
713 msgDialog.ShowModal();
718 if (csvFile.IsOpened()) {
720 csvFile.AddLine(GetActiveCurvesCSV());
726wxString ChartView::GetActiveCurvesCSV()
728 std::vector<PlotData*> activePlotDataList;
729 GetActivePlotData(m_treeCtrl->GetRootItem(), activePlotDataList);
731 std::vector<double> xValues;
735 bool foundXAxis =
false;
736 for (
auto it = activePlotDataList.begin(), itEnd = activePlotDataList.end(); it != itEnd; ++it) {
738 if (data->GetAxis() == 1) {
739 xValues = data->GetValues();
740 xName = data->GetName();
742 activePlotDataList.erase(it);
753 wxString csvText = xName +
";";
755 for (
auto it = activePlotDataList.begin(), itEnd = activePlotDataList.end(); it != itEnd; ++it) {
757 csvText += data->GetName() +
";";
759 csvText[csvText.length() - 1] =
'\n';
761 for (
unsigned int i = 0; i < xValues.size(); ++i) {
762 csvText += wxString::FromCDouble(xValues[i], 13) +
";";
763 for (
unsigned int j = 0; j < activePlotDataList.size(); ++j) {
765 if (i < activePlotDataList[j]->GetValues().size()) {
766 value = activePlotDataList[j]->GetValues()[i];
768 csvText += wxString::FromCDouble(value, 13) +
";";
770 csvText[csvText.length() - 1] =
'\n';
774 for (
auto it = activePlotDataList.begin(); it != activePlotDataList.end(); ++it) {
777 activePlotDataList.clear();
782wxTreeItemId ChartView::GetActivePlotData(wxTreeItemId root, std::vector<PlotData*>& plotDataList)
784 wxTreeItemIdValue cookie;
785 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
788 while (item.IsOk()) {
789 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(item))) {
790 if (data->IsPlot() || data->GetAxis() == 1) {
791 wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
795 dataCopy->SetName(data->GetName() +
" (" + parentName +
")");
796 plotDataList.push_back(dataCopy);
800 if (m_treeCtrl->ItemHasChildren(item)) {
801 wxTreeItemId nextChild = GetActivePlotData(item, plotDataList);
802 if (nextChild.IsOk())
return nextChild;
804 item = m_treeCtrl->GetNextChild(root, cookie);
807 wxTreeItemId dummyID;
810void ChartView::DrawChartDir()
812 int gridColour = 0xEAEAEA;
813 int bgColour = 0xFFFFFF;
814 int labelColour = 0x000000;
817 gridColour = 0x3D3D3D;
818 labelColour = 0xA0A0A0;
820 if (m_hideGrid) gridColour = Chart::Transparent;
822 XYChart* chartDir =
new XYChart(std::max(400, m_chartViewerSize.GetWidth()), std::max(300, m_chartViewerSize.GetHeight()), bgColour);
824 wxString title = m_pgPropChartTitle->GetValueAsString();
826 if (!title.IsEmpty()) {
827 chartDir->addTitle(title,
"arial.ttf", 12, labelColour);
831 LegendBox* box =
nullptr;
833 box = chartDir->addLegend(0, 0,
false,
"arial.ttf", 10);
834 box->setBackground(Chart::Transparent, Chart::Transparent);
835 box->setPos(m_pgPropMarginsLeft->GetValue().GetLong(), m_pgPropMarginsUp->GetValue().GetLong() + titleSize);
836 box->setFontColor(labelColour);
837 box->setLineStyleKey();
840 CalcXYLimits(m_treeCtrl->GetRootItem(), chartDir);
842 UpdateAllPlotsCharDir(m_treeCtrl->GetRootItem(), chartDir);
845 wxString xLabel = m_pgPropXLabel->GetValueAsString();
846 if (xLabel == _(
"auto")) xLabel = m_sugestXLabel;
847 wxString yLabel = m_pgPropYLabel->GetValueAsString();
848 if (yLabel == _(
"auto")) yLabel = m_sugestYLabel + GetUnitFromMagText(m_sugestYLabel);
849 int xLabelSize = 10, yLabelSize = 10;
851 if (xLabel.IsEmpty()) xLabelSize = 0;
852 if (yLabel.IsEmpty()) yLabelSize = 0;
854 chartDir->setPlotArea(
855 yLabelSize + m_pgPropMarginsLeft->GetValue().GetLong(),
856 titleSize + m_legendHeight + m_pgPropMarginsUp->GetValue().GetLong(),
857 chartDir->getWidth() - m_pgPropMarginsRight->GetValue().GetLong() - m_pgPropMarginsLeft->GetValue().GetLong() - yLabelSize,
858 chartDir->getHeight() - m_pgPropMarginsBot->GetValue().GetLong() - m_pgPropMarginsUp->GetValue().GetLong() - m_legendHeight - titleSize - xLabelSize,
859 bgColour, -1, -1, gridColour, gridColour);
860 chartDir->setClipping();
863 double xMin = 0, xMax = 0, yMin = 0, yMax = 0;
864 if (m_forceAxisLimits) {
865 xMin = m_pgPropXMin->GetValue().GetDouble();
866 xMax = m_pgPropXMax->GetValue().GetDouble();
867 yMin = m_pgPropYMin->GetValue().GetDouble();
868 yMax = m_pgPropYMax->GetValue().GetDouble();
876 yMin = m_yMin - 0.05 * (m_yMax - m_yMin);
877 yMax = m_yMax + 0.05 * (m_yMax - m_yMin);
878 m_pgPropXMin->SetValue(xMin);
879 m_pgPropXMax->SetValue(xMax);
880 m_pgPropYMin->SetValue(yMin);
881 m_pgPropYMax->SetValue(yMax);
883 m_chartViewerDir->setFullRange(
"x", xMin, xMax);
884 m_chartViewerDir->setFullRange(
"y", yMin, yMax);
887 double viewPortStartTime = m_chartViewerDir->getValueAtViewPort(
"x", m_chartViewerDir->getViewPortLeft());
888 double viewPortEndTime = m_chartViewerDir->getValueAtViewPort(
"x", m_chartViewerDir->getViewPortLeft() + m_chartViewerDir->getViewPortWidth());
890 chartDir->xAxis()->setTickDensity(20);
891 chartDir->xAxis()->setLinearScale(viewPortStartTime, viewPortEndTime);
892 chartDir->xAxis()->setLabelFormat(wxString::Format(
"{value|2~%c}", DotOrComma()));
893 chartDir->xAxis()->setColors(labelColour, labelColour);
894 chartDir->xAxis()->setTitle(xLabel,
"arial.ttf", 10, labelColour);
896 chartDir->yAxis()->setLabelFormat(wxString::Format(
"{value|2~%c}", DotOrComma()));
897 chartDir->yAxis()->setColors(labelColour, labelColour);
898 chartDir->yAxis()->setTitle(yLabel,
"arial.ttf", 10, labelColour);
899 m_chartViewerDir->syncLinearAxisWithViewPort(
"y", chartDir->yAxis());
902 DrawTrackLine(chartDir);
905 if (m_chartViewerDir->getChart() !=
nullptr)
907 delete m_chartViewerDir->getChart();
910 m_chartViewerDir->setChart(chartDir);
912 if (m_showLeg && box !=
nullptr) {
913 if (std::abs(m_legendHeight - box->getHeight()) > 1) {
914 m_legendHeight = box->getHeight();
920void ChartView::OnViewPortChanged(wxCommandEvent& event)
922 if (m_chartViewerDir->needUpdateChart()) DrawChartDir();
926void ChartView::OnMouseMovePlotArea(wxCommandEvent& event)
929 const int grabDist = 8;
931 int mouseX = m_chartViewerDir->getChartMouseX();
932 PlotArea* plotArea =
static_cast<XYChart*
>(m_chartViewerDir->getChart())->getPlotArea();
935 bool moveTrackLine =
false;
937 if (m_chartViewerDir->getMouseUsage() == Chart::MouseUsageDefault && wxGetMouseState().LeftIsDown()) {
939 SetCursor(wxCURSOR_SIZEWE);
940 moveTrackLine =
true;
943 if (std::abs(mouseX - m_trackLinePos) <= grabDist && !m_chartViewerDir->IsSelectionRectVisible()) {
944 SetCursor(wxCURSOR_SIZEWE);
945 m_chartViewerDir->setMouseUsage(Chart::MouseUsageDefault);
947 else if (!wxGetMouseState().LeftIsDown()) {
948 SetCursor(wxCURSOR_ARROW);
949 m_chartViewerDir->setMouseUsage(Chart::MouseUsageZoomIn);
953 m_trackLinePos = mouseX;
954 DrawTrackLine(
static_cast<XYChart*
>(m_chartViewerDir->getChart()));
955 m_chartViewerDir->updateDisplay();
962void ChartView::DrawTrackLine(XYChart* chartDir)
964 chartDir->initDynamicLayer();
966 double xValue = chartDir->getNearestXValue(m_trackLinePos);
967 int xCoor = chartDir->getXCoor(xValue);
968 chartDir->getDrawArea()->line(xCoor, chartDir->getPlotArea()->getTopY(), xCoor, chartDir->getPlotArea()->getBottomY(), 0x888888, 3);
970 std::ostringstream xlabel;
973 xlabel <<
"<*font,bgColor=000000*> " << chartDir->formatValue(xValue, wxString::Format(
"{value|P4~%c}", DotOrComma())) <<
" <*/font*>";
974 TTFText* text = chartDir->getDrawArea()->text(xlabel.str().c_str(),
"arialbd.ttf", 10);
975 int xLabelPos = std::max(0, std::min(xCoor - text->getWidth() / 2, chartDir->getWidth() - text->getWidth()));
976 text->draw(xLabelPos, chartDir->getPlotArea()->getBottomY() + 3, 0xffffff);
979 for (
int i = 0; i < chartDir->getLayerCount(); ++i)
981 Layer* layer = chartDir->getLayerByZ(i);
984 int xIndex = layer->getXIndexOf(xValue);
987 for (
int j = 0; j < layer->getDataSetCount(); ++j)
989 DataSet* dataSet = layer->getDataSetByZ(j);
990 const char* dataSetName = dataSet->getDataName();
993 int color = dataSet->getDataColor();
994 int yCoor = chartDir->getYCoor(dataSet->getPosition(xIndex), dataSet->getUseYAxis());
997 if ((yCoor >= chartDir->getPlotArea()->getTopY()) && (yCoor <= chartDir->getPlotArea()->getBottomY()) &&
998 (color != Chart::Transparent) && dataSetName && *dataSetName)
1000 chartDir->getDrawArea()->circle(xCoor, yCoor, 4, 4, color, color);
1002 std::ostringstream label;
1005 label <<
"<*font,bgColor=" << std::hex << m_rawDataColour[color] <<
"*> " << chartDir->formatValue(dataSet->getValue(xIndex), wxString::Format(
"{value|P4~%c}", DotOrComma())) <<
" <*font*>";
1006 text = chartDir->getDrawArea()->text(label.str().c_str(),
"arialbd.ttf", 10);
1011 if (xCoor <= (chartDir->getPlotArea()->getLeftX() + chartDir->getPlotArea()->getRightX()) / 2)
1013 text->draw(xCoor + 6, yCoor, 0xffffff, Chart::Left);
1017 text->draw(xCoor - 6, yCoor, 0xffffff, Chart::Right);
1025wxString ChartView::GetUnitFromMagText(wxString magText)
1027 wxString unitText =
" (p.u.)";
1028 if (magText.IsEmpty()) unitText =
"";
1029 else if (magText == _(
"Angle")) unitText =
" (°)";
1030 else if (magText == _(
"Delta")) unitText =
" (°)";
1031 else if (magText == _(
"Frequency")) unitText =
" (Hz)";
1032 else if (magText == _(
"Velocity")) unitText =
" (rad/s)";
1033 else if (magText == _(
"Slip")) unitText =
" (%)";
1037wxTreeItemId ChartView::CalcXYLimits(wxTreeItemId root, XYChart* chartDir)
1039 wxTreeItemIdValue cookie;
1040 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
1043 while (item.IsOk()) {
1044 if (
PlotData* data =
dynamic_cast<PlotData*
>(m_treeCtrl->GetItemData(item))) {
1045 if (data->IsPlot()) {
1046 wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
1048 std::vector<double> yValues = data->GetValues();
1049 if (yValues.size() == 0) {
1050 item = m_treeCtrl->GetNextChild(root, cookie);
1054 double minY = *std::min_element(yValues.begin(), yValues.end());
1055 double maxY = *std::max_element(yValues.begin(), yValues.end());
1057 m_firstPlot =
false;
1061 m_xMin = *std::min_element(m_xAxisValues.begin(), m_xAxisValues.end());
1062 m_xMax = *std::max_element(m_xAxisValues.begin(), m_xAxisValues.end());
1065 if (minY < m_yMin) m_yMin = minY;
1066 if (maxY > m_yMax) m_yMax = maxY;
1071 if (m_treeCtrl->ItemHasChildren(item)) {
1072 wxTreeItemId nextChild = CalcXYLimits(item, chartDir);
1073 if (nextChild.IsOk())
return nextChild;
1075 item = m_treeCtrl->GetNextChild(root, cookie);
1078 wxTreeItemId dummyID;
1082void ChartView::OnResize(wxSizeEvent& event)
1084 if (m_plotLib == PlotLib::wxCHART_DIR) {
1085 m_chartViewerSize =
event.GetSize() - wxSize(m_treeCtrl->GetSize().GetWidth(), 60);
1087 m_chartViewerDir->updateViewPort(
true,
false);
1092void ChartView::OnClose(wxCloseEvent& event)
This class is responsible to manage the graphical data of electromechanical result to be plotted on c...