Power System Platform  2026w23a-beta
Loading...
Searching...
No Matches
ChartView.cpp
1/*
2 * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#include "ChartView.h"
19#include "../utils/ElementPlotData.h"
20
21#include <sstream>
22#include <wx/mstream.h>
23
24ChartView::ChartView(wxWindow* parent, std::vector<ElementPlotData> epdList, std::vector<double> time, PlotLib plotLib)
25 : ChartViewBase(parent)
26{
27 m_epdList = epdList;
28 m_time = time;
29 m_xAxisValues = time;
30 m_plotLib = plotLib;
31
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);
36
37 // Create color property.
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)));
41
42 // Set margins and axis limit to composed mode.
43 m_pgPropMargins->SetValue(wxT("<composed>"));
44 m_pgMgr->Collapse(m_pgPropMargins);
45 m_pgPropAxisLimit->SetValue(wxT("<composed>"));
46 m_pgMgr->Collapse(m_pgPropAxisLimit);
47
48 // Add line type choices
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);
56 }
57
58 if (m_plotLib == PlotLib::wxMATH_PLOT) {
59 SetMPWindow();
60 GetSizer()->Add(m_mpWindow, 1, wxEXPAND, WXC_FROM_DIP(5));
61 }
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));
73
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);
77
78 m_pgPropMarginsUp->SetValue(10);
79 m_pgPropMarginsLeft->SetValue(50);
80 m_pgPropMarginsRight->SetValue(40);
81 m_pgPropMarginsBot->SetValue(40);
82
83 m_pgPropXLabel->SetValue(_("auto"));
84 m_pgPropYLabel->SetValue(_("auto"));
85 }
86 SetTreectrl();
87 Layout();
88 SetInitialSize();
89
90 BuildColourList();
91
92 //if (m_plotLib == PlotLib::wxCHART_DIR) {
93 // DrawChartDir();
94 //}
95}
96
97ChartView::~ChartView()
98{
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);
103 }
104}
105void ChartView::SetMPWindow()
106{
107 m_mpWindow = new mpWindow(this, wxID_ANY);
108
109 m_mpWindow->SetDoubleBuffered(true);
110
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);
118
119 m_leg = new mpInfoLegend(wxRect(200, 20, 40, 40), wxWHITE_BRUSH);
120 m_coords = new mpInfoCoords(wxRect(0, 0, 0, 0), wxWHITE_BRUSH);
121
122 m_chartTitle = new mpText("", 50, 0);
123 wxFont chartTitleFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
124 m_chartTitle->SetFont(chartTitleFont);
125
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);
131
132 m_leg->SetVisible(m_showLeg);
133 m_coords->SetVisible(m_showCoords);
134
135 m_mpWindow->EnableDoubleBuffer(true);
136 m_mpWindow->LockAspect(false);
137 Fit();
138}
139
140void ChartView::SetTreectrl()
141{
142 wxTreeItemId rootID = m_treeCtrl->AddRoot(wxT("root"));
143 m_treeTimeID = m_treeCtrl->AppendItem(rootID, _("Time"));
144 m_treeCtrl->SetItemTextColour(m_treeTimeID, *wxRED);
145
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;
148
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");
160
161 wxTreeItemId rootItemID[static_cast<unsigned int>(ElementPlotData::CurveType::NUM_ELEMENTS)];
162
163 for (auto it = m_epdList.begin(), itEnd = m_epdList.end(); it != itEnd; ++it) {
164 ElementPlotData data = *it;
165 unsigned int curveType = static_cast<unsigned int>(data.GetCurveType());
166
167 if (firstElement[curveType]) {
168 rootItemID[curveType] = m_treeCtrl->AppendItem(rootID, rootElementName[curveType]);
169 firstElement[curveType] = false;
170 }
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));
174 }
175 }
176}
177
178void ChartView::OnPropertyGridChange(wxPropertyGridEvent& event)
179{
180 bool fit = false;
181 wxString pName = event.GetPropertyName();
182 if (pName.empty()) return;
183
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);
189 if (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);
194 }
195 else {
196 m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(), false);
197 }
198 fit = true;
199 }
200 else if (pName == _("Color")) {
201 wxColour colour;
202 colour << m_pgPropColor->GetValue();
203 data->SetColour(colour);
204 }
205 else if (pName == _("Thickness")) {
206 data->SetThick(m_pgProplineThick->GetValue().GetInteger());
207 }
208 else if (pName == _("Type")) {
209 data->SetPenType(static_cast<wxPenStyle>(m_pgProplineType->GetValue().GetInteger()));
210 }
211 else if (pName == _("Axis")) {
212 int axis = m_pgProplineAxis->GetValue().GetInteger();
213 if (axis == 1) { // Y
214 // All lines to Y axis
215 AllToYAxis(m_treeCtrl->GetRootItem());
216 // Select curve to X axis
217 m_treeCtrl->SetItemTextColour(m_treeCtrl->GetSelection(), *wxRED);
218 m_xAxisValues = data->GetValues();
219 m_sugestXLabel = data->GetName() + GetUnitFromMagText(data->GetName());
220 }
221 data->SetAxis(axis);
222 fit = true;
223 }
224 }
225 }
226
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();
232 }
233 else if (m_plotLib == PlotLib::wxCHART_DIR) {
234 m_chartViewerDir->updateViewPort(true, false);
235 event.Skip();
236 }
237 }
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();
243 }
244 else if (m_plotLib == PlotLib::wxCHART_DIR) {
245 m_forceAxisLimits = true;
246 }
247 }
248 UpdatePlot(fit);
249 event.Skip();
250}
251
252void ChartView::OnRightClickDown(wxMouseEvent& event)
253{
254 Fit();
255}
256
257void ChartView::OnMenuDarkThemeClick(wxCommandEvent& event)
258{
259 m_darkTheme = event.IsChecked();
260
261 if (m_plotLib == PlotLib::wxMATH_PLOT) {
262 wxColour grey(96, 96, 96);
263
264 if (m_darkTheme) {
265 m_mpWindow->SetColourTheme(*wxBLACK, *wxWHITE, grey);
266 m_leg->SetBrush(*wxBLACK_BRUSH);
267 m_coords->SetBrush(*wxBLACK_BRUSH);
268 }
269 else {
270 m_mpWindow->SetColourTheme(*wxWHITE, *wxBLACK, grey);
271 m_leg->SetBrush(*wxWHITE_BRUSH);
272 m_coords->SetBrush(*wxWHITE_BRUSH);
273 }
274
275 m_mpWindow->UpdateAll();
276 }
277 else if (m_plotLib == PlotLib::wxCHART_DIR) {
278 DrawChartDir();
279 }
280}
281
282void ChartView::OnMenuSaveImageClick(wxCommandEvent& event)
283{
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();
289
290 wxScreenDC dcScreen;
291 wxBitmap screenshot(width, height);
292
293 wxMemoryDC memDC;
294 memDC.SelectObject(screenshot);
295
296 memDC.Blit(0, 0, width, height, &dcScreen, x, y);
297 memDC.SelectObject(wxNullBitmap);
298
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;
304
305 wxFileName imagePath(saveFileDialog.GetPath());
306 wxBitmapType imageType = wxBITMAP_TYPE_BMP;
307
308 if (imagePath.GetExt() == "png")
309 imageType = wxBITMAP_TYPE_PNG;
310 else if (imagePath.GetExt() == "jpg")
311 imageType = wxBITMAP_TYPE_JPEG;
312
313 screenshot.SaveFile(imagePath.GetFullPath(), imageType);
314 }
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;
321
322 wxFileName imagePath(saveFileDialog.GetPath());
323 m_chartViewerDir->getChart()->makeChart(imagePath.GetFullPath().ToUTF8());
324 }
325}
326
327void ChartView::OnMenuSendClipClick(wxCommandEvent& event)
328{
329 wxBitmap screenshot;
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();
335
336 wxScreenDC dcScreen;
337 screenshot = wxBitmap(width, height);
338
339 wxMemoryDC memDC;
340 memDC.SelectObject(screenshot);
341
342 memDC.Blit(0, 0, width, height, &dcScreen, x, y);
343 memDC.SelectObject(wxNullBitmap);
344 }
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));
349 }
350
351 if (screenshot.IsOk()) {
352 if (wxTheClipboard->Open()) {
353 wxTheClipboard->SetData(new wxBitmapDataObject(screenshot));
354 wxTheClipboard->Close();
355
356 wxMessageDialog msgDialog(this, _("Chart send to clipboard"), _("Info"), wxOK | wxICON_INFORMATION,
357 wxDefaultPosition);
358 msgDialog.ShowModal();
359 }
360 else {
361 wxMessageDialog msgDialog(this, _("It was not possible to send to clipboard"), _("Error"), wxOK | wxICON_ERROR,
362 wxDefaultPosition);
363 msgDialog.ShowModal();
364 }
365 }
366 else {
367 wxMessageDialog msgDialog(this, _("It was not possible to create the screenshot"), _("Error"), wxOK | wxICON_ERROR,
368 wxDefaultPosition);
369 msgDialog.ShowModal();
370 }
371}
372
373void ChartView::OnMenuShowCoordinatesClick(wxCommandEvent& event)
374{
375 m_showCoords = event.IsChecked();
376 if (m_plotLib == PlotLib::wxMATH_PLOT) {
377 m_coords->SetVisible(m_showCoords);
378 m_mpWindow->UpdateAll();
379 }
380 else if (m_plotLib == PlotLib::wxCHART_DIR) {
381 if (m_showCoords) {
382 XYChart* chart = static_cast<XYChart*>(m_chartViewerDir->getChart());
383 m_trackLinePos = chart->getPlotArea()->getLeftX() + (int)(chart->getPlotArea()->getWidth() * 0.5);
384 }
385 DrawChartDir();
386 }
387}
388
389void ChartView::OnMenuShowGridClick(wxCommandEvent& event)
390{
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();
396 }
397 else if (m_plotLib == PlotLib::wxCHART_DIR) {
398 DrawChartDir();
399 }
400}
401
402void ChartView::OnMenuShowLabelClick(wxCommandEvent& event)
403{
404 m_showLeg = event.IsChecked();
405
406 if (m_plotLib == PlotLib::wxMATH_PLOT) {
407 m_leg->SetVisible(m_showLeg);
408 m_mpWindow->UpdateAll();
409 }
410 else if (m_plotLib == PlotLib::wxCHART_DIR) {
411 if (!m_showLeg) m_legendHeight = 0;
412 DrawChartDir();
413 }
414}
415
416void ChartView::Fit()
417{
418 if (m_plotLib == PlotLib::wxMATH_PLOT) {
419 m_mpWindow->Fit();
420 double bBox[4];
421 m_mpWindow->GetBoundingBox(bBox);
422
423 m_pgPropXMin->SetValue(bBox[0]);
424 m_pgPropXMax->SetValue(bBox[1]);
425 m_pgPropYMin->SetValue(bBox[2]);
426 m_pgPropYMax->SetValue(bBox[3]);
427 }
428 else if (m_plotLib == PlotLib::wxCHART_DIR) {
429 m_forceAxisLimits = false;
430 // Reset viewport
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);
437
438 // redraw the chart
439 m_chartViewerDir->updateViewPort(true, false);
440 }
441}
442
443void ChartView::UpdatePlot(bool fit)
444{
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);
449
450 // GoAllTrees(treeCtrl_ChartSelection->GetRootItem());
451 UpdateAllPlots(m_treeCtrl->GetRootItem());
452
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);
457
458 m_xaxis->SetDrawOutsideMargins(false);
459 m_yaxis->SetDrawOutsideMargins(false);
460 m_xaxis->SetTicks(m_hideGrid);
461 m_yaxis->SetTicks(m_hideGrid);
462
463 mpText* chartTitle = new mpText(m_pgPropChartTitle->GetValueAsString(), 50, 0);
464 wxFont chartTitleFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
465 chartTitle->SetFont(chartTitleFont);
466
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);
472
473 m_leg->SetVisible(m_showLeg);
474 m_coords->SetVisible(m_showCoords);
475
476 if (fit) Fit();
477
478 wxColour grey(96, 96, 96);
479 if (m_darkTheme) {
480 m_mpWindow->SetColourTheme(*wxBLACK, *wxWHITE, grey);
481 m_leg->SetBrush(*wxBLACK_BRUSH);
482 m_coords->SetBrush(*wxBLACK_BRUSH);
483 }
484 else {
485 m_mpWindow->SetColourTheme(*wxWHITE, *wxBLACK, grey);
486 m_leg->SetBrush(*wxWHITE_BRUSH);
487 m_coords->SetBrush(*wxWHITE_BRUSH);
488 }
489 }
490 else if (m_plotLib == PlotLib::wxCHART_DIR) {
491 DrawChartDir();
492 if (fit) Fit();
493 }
494}
495
496void ChartView::OnTreeItemActivated(wxTreeEvent& event)
497{
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());
502 if (isPlotting) {
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);
507 }
508 else {
509 m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(), false);
510 }
511 UpdatePlot(true);
512 }
513
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)");
519 UpdatePlot(true);
520 }
521
522 event.Skip();
523}
524
525void ChartView::OnTreeItemSelectionChanged(wxTreeEvent& event)
526{
527 //if (PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(m_selectedItemID)))
528 // data->SetHighlight(false);
529 if (m_selectedItemID.IsOk()) {
530 if (PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(m_selectedItemID))) {
531 data->SetHighlight(false);
532 }
533 }
534
535 m_selectedItemID = event.GetItem();
536
537 if (PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(m_selectedItemID))) {
538 m_pgPropDraw->SetValue(data->IsPlot());
539 wxVariant colour;
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);
546 }
547 if (m_plotLib == PlotLib::wxCHART_DIR) {
548 m_chartViewerDir->updateViewPort(true, false);
549 }
550 event.Skip();
551}
552
553void ChartView::BuildColourList()
554{
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();
571}
572
573wxColour ChartView::GetNextColour()
574{
575 if (*m_itColourList == *wxBLACK)
576 m_itColourList = m_colourList.begin();
577 else
578 ++m_itColourList;
579
580 return *m_itColourList;
581}
582
583wxTreeItemId ChartView::AllToYAxis(wxTreeItemId root)
584{
585 wxTreeItemIdValue cookie;
586 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
587 wxTreeItemId child;
588
589 while (item.IsOk()) {
590 m_treeCtrl->SetItemTextColour(item, *wxBLACK);
591 if (PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(item))) data->SetAxis(0); // X axis.
592
593 if (m_treeCtrl->ItemHasChildren(item)) {
594 wxTreeItemId nextChild = AllToYAxis(item);
595 if (nextChild.IsOk()) return nextChild;
596 }
597 item = m_treeCtrl->GetNextChild(root, cookie);
598 }
599
600 wxTreeItemId dummyID;
601 return dummyID;
602}
603
604wxTreeItemId ChartView::UpdateAllPlots(wxTreeItemId root)
605{
606 wxTreeItemIdValue cookie;
607 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
608 wxTreeItemId child;
609
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);
621
622 m_mpWindow->AddLayer(newLayer);
623 }
624 }
625
626 if (m_treeCtrl->ItemHasChildren(item)) {
627 wxTreeItemId nextChild = UpdateAllPlots(item);
628 if (nextChild.IsOk()) return nextChild;
629 }
630 item = m_treeCtrl->GetNextChild(root, cookie);
631 }
632
633 wxTreeItemId dummyID;
634 return dummyID;
635}
636
637wxTreeItemId ChartView::UpdateAllPlotsCharDir(wxTreeItemId root, XYChart* chartDir)
638{
639 wxTreeItemIdValue cookie;
640 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
641 wxTreeItemId child;
642
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));
647
648 std::vector<double> yValues = data->GetValues();
649
650
651
652 LineLayer* layer = chartDir->addLineLayer();
653 layer->setFastLineMode();
654 layer->setLineWidth(data->GetThick());
655 layer->setXData(DoubleArray(&m_xAxisValues[0], m_xAxisValues.size()));
656
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;
660 //layer->addDataSet(DoubleArray(&data->GetValues()[0] + startIndex, endIndex - startIndex + 1), dataColour, data->GetName() + " (" + parentName + ")");
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;
668
669 layer->addDataSet(DoubleArray(&yValues[0], yValues.size()), dataColour, data->GetName() + " (" + parentName + ")");
670
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);
678 }
679
680 if (m_firstPlot) {
681 m_firstPlot = false;
682 m_sugestYLabel = data->GetName();
683 }
684 else {
685 if (m_sugestYLabel.IsEmpty() || (m_sugestYLabel != data->GetName())) m_sugestYLabel = "";
686 }
687 }
688 }
689
690 if (m_treeCtrl->ItemHasChildren(item)) {
691 wxTreeItemId nextChild = UpdateAllPlotsCharDir(item, chartDir);
692 if (nextChild.IsOk()) return nextChild;
693 }
694 item = m_treeCtrl->GetNextChild(root, cookie);
695 }
696
697
698 wxTreeItemId dummyID;
699 return dummyID;
700}
701
702void ChartView::OnMenuExpCSVClick(wxCommandEvent& event)
703{
704 wxFileDialog saveFileDialog(this, _("Save CSV file"), "", "", "CSV file (*.csv)|*.csv",
705 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
706 if (saveFileDialog.ShowModal() == wxID_CANCEL) return;
707
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();
714 }
715 }
716 else
717 csvFile.Open();
718 if (csvFile.IsOpened()) {
719 csvFile.Clear();
720 csvFile.AddLine(GetActiveCurvesCSV());
721 csvFile.Write();
722 csvFile.Close();
723 }
724}
725
726wxString ChartView::GetActiveCurvesCSV()
727{
728 std::vector<PlotData*> activePlotDataList;
729 GetActivePlotData(m_treeCtrl->GetRootItem(), activePlotDataList);
730
731 std::vector<double> xValues;
732 wxString xName = "";
733
734 // Find X axis curve, if none is found, X is the m_time.
735 bool foundXAxis = false;
736 for (auto it = activePlotDataList.begin(), itEnd = activePlotDataList.end(); it != itEnd; ++it) {
737 PlotData* data = *it;
738 if (data->GetAxis() == 1) {
739 xValues = data->GetValues();
740 xName = data->GetName();
741 foundXAxis = true;
742 activePlotDataList.erase(it);
743 delete data;
744 break;
745 }
746 }
747 if (!foundXAxis) {
748 xValues = m_time;
749 xName = _("Time");
750 }
751
752 // Build CSV text.
753 wxString csvText = xName + ";";
754 // Header
755 for (auto it = activePlotDataList.begin(), itEnd = activePlotDataList.end(); it != itEnd; ++it) {
756 PlotData* data = *it;
757 csvText += data->GetName() + ";";
758 }
759 csvText[csvText.length() - 1] = '\n';
760 // Values
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) {
764 double value = 0.0;
765 if (i < activePlotDataList[j]->GetValues().size()) {
766 value = activePlotDataList[j]->GetValues()[i];
767 }
768 csvText += wxString::FromCDouble(value, 13) + ";";
769 }
770 csvText[csvText.length() - 1] = '\n';
771 }
772
773 // Clear active plot data vector.
774 for (auto it = activePlotDataList.begin(); it != activePlotDataList.end(); ++it) {
775 delete(*it);
776 }
777 activePlotDataList.clear();
778
779 return csvText;
780}
781
782wxTreeItemId ChartView::GetActivePlotData(wxTreeItemId root, std::vector<PlotData*>& plotDataList)
783{
784 wxTreeItemIdValue cookie;
785 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
786 wxTreeItemId child;
787
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));
792
793 PlotData* dataCopy = new PlotData();
794 *dataCopy = *data;
795 dataCopy->SetName(data->GetName() + " (" + parentName + ")");
796 plotDataList.push_back(dataCopy);
797 }
798 }
799
800 if (m_treeCtrl->ItemHasChildren(item)) {
801 wxTreeItemId nextChild = GetActivePlotData(item, plotDataList);
802 if (nextChild.IsOk()) return nextChild;
803 }
804 item = m_treeCtrl->GetNextChild(root, cookie);
805 }
806
807 wxTreeItemId dummyID;
808 return dummyID;
809}
810void ChartView::DrawChartDir()
811{
812 int gridColour = 0xEAEAEA;
813 int bgColour = 0xFFFFFF;
814 int labelColour = 0x000000;
815 if (m_darkTheme) {
816 bgColour = 0x303030;
817 gridColour = 0x3D3D3D;
818 labelColour = 0xA0A0A0;
819 }
820 if (m_hideGrid) gridColour = Chart::Transparent;
821
822 XYChart* chartDir = new XYChart(std::max(400, m_chartViewerSize.GetWidth()), std::max(300, m_chartViewerSize.GetHeight()), bgColour);
823
824 wxString title = m_pgPropChartTitle->GetValueAsString();
825 int titleSize = 0;
826 if (!title.IsEmpty()) {
827 chartDir->addTitle(title, "arial.ttf", 12, labelColour);
828 titleSize = 12;
829 }
830
831 LegendBox* box = nullptr;
832 if (m_showLeg) {
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();
838 }
839 m_firstPlot = true;
840 CalcXYLimits(m_treeCtrl->GetRootItem(), chartDir);
841 m_firstPlot = true;
842 UpdateAllPlotsCharDir(m_treeCtrl->GetRootItem(), chartDir);
843
844
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;
850 // If the label is empty, the size is 0.
851 if (xLabel.IsEmpty()) xLabelSize = 0;
852 if (yLabel.IsEmpty()) yLabelSize = 0;
853
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();
861
862 //DoubleArray timeArray(&m_time[0], m_time.size());
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();
869 }
870 else {
871 //xMin = m_xAxisValues[0];
872 xMin = m_xMin;
873 //xMax = m_time[m_time.size() - 1];
874 //xMax = m_xAxisValues[m_xAxisValues.size() - 1];
875 xMax = m_xMax;
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);
882 }
883 m_chartViewerDir->setFullRange("x", xMin, xMax);
884 m_chartViewerDir->setFullRange("y", yMin, yMax);
885
886 // Get the start date and end date that are visible on the chart.
887 double viewPortStartTime = m_chartViewerDir->getValueAtViewPort("x", m_chartViewerDir->getViewPortLeft());
888 double viewPortEndTime = m_chartViewerDir->getValueAtViewPort("x", m_chartViewerDir->getViewPortLeft() + m_chartViewerDir->getViewPortWidth());
889
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);
895
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());
900
901 if (m_showCoords) {
902 DrawTrackLine(chartDir);
903 }
904
905 if (m_chartViewerDir->getChart() != nullptr)
906 {
907 delete m_chartViewerDir->getChart();
908 }
909 // Set the chart image to the WinChartViewer
910 m_chartViewerDir->setChart(chartDir);
911
912 if (m_showLeg && box != nullptr) {
913 if (std::abs(m_legendHeight - box->getHeight()) > 1) {
914 m_legendHeight = box->getHeight();
915 DrawChartDir();
916 }
917 }
918}
919
920void ChartView::OnViewPortChanged(wxCommandEvent& event)
921{
922 if (m_chartViewerDir->needUpdateChart()) DrawChartDir();
923 event.Skip();
924}
925
926void ChartView::OnMouseMovePlotArea(wxCommandEvent& event)
927{
928 if (m_showCoords) {
929 const int grabDist = 8;
930
931 int mouseX = m_chartViewerDir->getChartMouseX();
932 PlotArea* plotArea = static_cast<XYChart*>(m_chartViewerDir->getChart())->getPlotArea();
933 //m_trackLinePos = (std::min)(plotArea->getRightX(), (std::max)(plotArea->getLeftX(), mouseX - grabDist));
934
935 bool moveTrackLine = false;
936
937 if (m_chartViewerDir->getMouseUsage() == Chart::MouseUsageDefault && wxGetMouseState().LeftIsDown()) {
938 // Lock in move track line
939 SetCursor(wxCURSOR_SIZEWE);
940 moveTrackLine = true;
941 }
942
943 if (std::abs(mouseX - m_trackLinePos) <= grabDist && !m_chartViewerDir->IsSelectionRectVisible()) {
944 SetCursor(wxCURSOR_SIZEWE);
945 m_chartViewerDir->setMouseUsage(Chart::MouseUsageDefault);
946 }
947 else if (!wxGetMouseState().LeftIsDown()) {
948 SetCursor(wxCURSOR_ARROW);
949 m_chartViewerDir->setMouseUsage(Chart::MouseUsageZoomIn);
950 }
951
952 if (moveTrackLine) {
953 m_trackLinePos = mouseX;
954 DrawTrackLine(static_cast<XYChart*>(m_chartViewerDir->getChart()));
955 m_chartViewerDir->updateDisplay();
956 }
957
958 }
959 event.Skip();
960}
961
962void ChartView::DrawTrackLine(XYChart* chartDir)
963{
964 chartDir->initDynamicLayer();
965
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);
969
970 std::ostringstream xlabel;
971
972 //xlabel << "<*font,bgColor=000000*> " << chartDir->xAxis()->getFormattedLabel(xValue) << " s <*/font*>";
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);
977 text->destroy();
978
979 for (int i = 0; i < chartDir->getLayerCount(); ++i)
980 {
981 Layer* layer = chartDir->getLayerByZ(i);
982
983 // The data array index of the x-value
984 int xIndex = layer->getXIndexOf(xValue);
985
986 // Iterate through all the data sets in the layer
987 for (int j = 0; j < layer->getDataSetCount(); ++j)
988 {
989 DataSet* dataSet = layer->getDataSetByZ(j);
990 const char* dataSetName = dataSet->getDataName();
991
992 // Get the color, name and position of the data label
993 int color = dataSet->getDataColor();
994 int yCoor = chartDir->getYCoor(dataSet->getPosition(xIndex), dataSet->getUseYAxis());
995
996 // Draw a track dot with a label next to it for visible data points in the plot area
997 if ((yCoor >= chartDir->getPlotArea()->getTopY()) && (yCoor <= chartDir->getPlotArea()->getBottomY()) &&
998 (color != Chart::Transparent) && dataSetName && *dataSetName)
999 {
1000 chartDir->getDrawArea()->circle(xCoor, yCoor, 4, 4, color, color);
1001
1002 std::ostringstream label;
1003
1004 //wxMessageBox(wxString::Format("%d", i));
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);
1007 //log[dataSetName] = dataSet->getValue(xIndex);
1008
1009 // Draw the label on the right side of the dot if the mouse is on the left side the
1010 // chart, and vice versa. This ensures the label will not go outside the chart image.
1011 if (xCoor <= (chartDir->getPlotArea()->getLeftX() + chartDir->getPlotArea()->getRightX()) / 2)
1012 {
1013 text->draw(xCoor + 6, yCoor, 0xffffff, Chart::Left);
1014 }
1015 else
1016 {
1017 text->draw(xCoor - 6, yCoor, 0xffffff, Chart::Right);
1018 }
1019 text->destroy();
1020 }
1021 }
1022 }
1023}
1024
1025wxString ChartView::GetUnitFromMagText(wxString magText)
1026{
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 = " (%)";
1034 return unitText;
1035}
1036
1037wxTreeItemId ChartView::CalcXYLimits(wxTreeItemId root, XYChart* chartDir)
1038{
1039 wxTreeItemIdValue cookie;
1040 wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
1041 wxTreeItemId child;
1042
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));
1047
1048 std::vector<double> yValues = data->GetValues();
1049 if (yValues.size() == 0) {
1050 item = m_treeCtrl->GetNextChild(root, cookie);
1051 continue;
1052 }
1053
1054 double minY = *std::min_element(yValues.begin(), yValues.end());
1055 double maxY = *std::max_element(yValues.begin(), yValues.end());
1056 if (m_firstPlot) {
1057 m_firstPlot = false;
1058 m_yMin = minY;
1059 m_yMax = maxY;
1060
1061 m_xMin = *std::min_element(m_xAxisValues.begin(), m_xAxisValues.end());
1062 m_xMax = *std::max_element(m_xAxisValues.begin(), m_xAxisValues.end());
1063 }
1064 else {
1065 if (minY < m_yMin) m_yMin = minY;
1066 if (maxY > m_yMax) m_yMax = maxY;
1067 }
1068 }
1069 }
1070
1071 if (m_treeCtrl->ItemHasChildren(item)) {
1072 wxTreeItemId nextChild = CalcXYLimits(item, chartDir);
1073 if (nextChild.IsOk()) return nextChild;
1074 }
1075 item = m_treeCtrl->GetNextChild(root, cookie);
1076 }
1077
1078 wxTreeItemId dummyID;
1079 return dummyID;
1080}
1081
1082void ChartView::OnResize(wxSizeEvent& event)
1083{
1084 if (m_plotLib == PlotLib::wxCHART_DIR) {
1085 m_chartViewerSize = event.GetSize() - wxSize(m_treeCtrl->GetSize().GetWidth(), 60);
1086 //m_chartViewerDir->Layout();
1087 m_chartViewerDir->updateViewPort(true, false);
1088 //DrawChartDir();
1089 }
1090 event.Skip();
1091}
1092void ChartView::OnClose(wxCloseEvent& event)
1093{
1094 Destroy();
1095}
This class is responsible to manage the graphical data of electromechanical result to be plotted on c...