25#include "../elements/Element.h"
26#include "../elements/ElementDataObject.h"
27#include "../elements/Text.h"
28#include "../elements/powerElement/Capacitor.h"
29#include "../elements/powerElement/HarmCurrent.h"
30#include "../elements/powerElement/IndMotor.h"
31#include "../elements/powerElement/Inductor.h"
32#include "../elements/powerElement/Line.h"
33#include "../elements/powerElement/Load.h"
34#include "../elements/powerElement/SyncGenerator.h"
35#include "../elements/powerElement/SyncMotor.h"
36#include "../elements/powerElement/Transformer.h"
37#include "../elements/powerElement/EMTElement.h"
39#include "../simulation/Electromechanical.h"
40#include "../simulation/Fault.h"
41#include "../simulation/PowerFlow.h"
42#include "../simulation/PowerQuality.h"
44#include "../utils/ElementPlotData.h"
46#include "../forms/FrequencyResponseForm.h"
48#include "../utils/Camera.h"
49#include "../utils/PropertiesData.h"
50#include "../utils/HMPlane.h"
51#include "../utils/FileHanding.h"
52#include "../utils/Path.h"
54#include <wx/busyinfo.h>
58Workspace::Workspace() : WorkspaceBase(nullptr)
61#ifdef SHOW_DEBUG_PANEL
63 m_debugFrame->SetTitle(_(
"Debug window: ") + m_name);
68 SetBackgroundColour(wxColour(255, 255, 255));
69 SetBackgroundStyle(wxBG_STYLE_PAINT);
72Workspace::Workspace(wxWindow* parent, wxString name, wxStatusBar* statusBar, wxAuiNotebook* auiNotebook)
73 : WorkspaceBase(parent)
76#ifdef SHOW_DEBUG_PANEL
78 m_debugFrame->SetTitle(_(
"Debug window: ") + m_name);
86 m_statusBar = statusBar;
87 m_auiNotebook = auiNotebook;
90 m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
92 for (
int i = 0; i < NUM_ELEMENTS; ++i) { m_elementNumber[i] = 1; }
94 const int widths[4] = { -3, -1, 100, 100 };
95 m_statusBar->SetStatusWidths(4, widths);
100 m_workspacePanel->SetBackgroundColour(wxColour(255, 255, 255));
101 m_workspacePanel->SetBackgroundStyle(wxBG_STYLE_PAINT);
105 m_width =
static_cast<float>(m_workspacePanel->GetSize().x) - 1.0;
106 m_height =
static_cast<float>(m_workspacePanel->GetSize().y) - 1.0;
112Workspace::~Workspace()
121 if (m_hmPlane)
delete m_hmPlane;
123 if (m_camera)
delete m_camera;
128 if (m_tipWindow)
delete m_tipWindow;
129 if (m_properties)
delete m_properties;
132void Workspace::OnPaint(wxPaintEvent& event)
134 wxBufferedPaintDC dc(m_workspacePanel);
136 wxGraphicsContext* gc = wxGraphicsContext::Create(dc);
145void Workspace::DrawScene(wxGraphicsContext* gc)
151 if (m_hmPlane && m_showHM) {
152 m_hmPlane->DrawDC(gc);
155 gc->Scale(m_camera->GetScale(), m_camera->GetScale());
156 gc->Translate(m_camera->GetTranslation().m_x, m_camera->GetTranslation().m_y);
159 for (
auto& element : m_elementList) {
160 element->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), gc);
165 Text* text =
new Text(wxPoint2DDouble(0.0, 0.0), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
167 text->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), gc);
171 for (
auto& text : m_textList) {
172 text->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), gc);
176 gc->SetPen(wxPen(wxColour(0, 125, 255, 255)));
177 gc->SetBrush(wxBrush(wxColour(0, 125, 255, 125)));
178 gc->DrawRectangle(m_selectionRect.m_x, m_selectionRect.m_y, m_selectionRect.m_width, m_selectionRect.m_height);
180 if (m_hmPlane && m_showHM) {
181 m_hmPlane->DrawLabelDC(gc);
186void Workspace::DrawScene(wxDC& dc)
189 if (m_hmPlane && m_showHM) {
190 m_hmPlane->DrawDC(dc);
193 dc.SetUserScale(m_camera->GetScale(), m_camera->GetScale());
194 dc.SetDeviceOrigin(m_camera->GetTranslation().m_x * m_camera->GetScale(), m_camera->GetTranslation().m_y * m_camera->GetScale());
198 for (
auto& element : m_elementList) {
199 element->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), dc);
204 Text* text =
new Text(wxPoint2DDouble(0.0, 0.0), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
206 text->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), dc);
210 for (
auto& text : m_textList) {
211 text->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), dc);
214 if (m_hmPlane && m_showHM) {
215 m_hmPlane->DrawLabelDC(dc);
219void Workspace::CopyToClipboard()
221 wxSize size = GetClientSize();
225 wxBitmap bitmap(size.x * scale, size.y * scale);
226 wxMemoryDC memDC(bitmap);
228 memDC.SetBackground(*wxWHITE_BRUSH);
231 wxGraphicsContext* gc = wxGraphicsContext::Create(memDC);
233 gc->Scale(scale, scale);
238 memDC.SelectObject(wxNullBitmap);
240 if (wxTheClipboard->Open())
242 wxTheClipboard->SetData(
new wxBitmapDataObject(bitmap));
243 wxTheClipboard->Close();
247void Workspace::ExportAsSVG(wxString path)
249 wxSize size = GetClientSize();
251 wxSVGFileDC svgDC(path, size.x, size.y);
253 svgDC.SetClippingRegion(wxRect(0, 0, size.x, size.y));
258void Workspace::OnLeftClickDown(wxMouseEvent& event)
260 wxPoint clickPoint =
event.GetPosition();
261 bool foundElement =
false;
263 bool showNewElementForm =
false;
264 bool clickOnSwitch =
false;
265 bool unselectAll =
true;
266 std::vector<Element*> notUnselectElementList;
267 std::vector<Text*> notUnselectTextList;
269 if (m_mode == WorkspaceMode::MODE_INSERT_TEXT || m_mode == WorkspaceMode::MODE_PASTE || m_mode == WorkspaceMode::MODE_DRAG_PASTE) {
270 m_mode = WorkspaceMode::MODE_EDIT;
273 else if (m_mode == WorkspaceMode::MODE_INSERT || m_mode == WorkspaceMode::MODE_DRAG_INSERT || m_mode == WorkspaceMode::MODE_DRAG_INSERT_TEXT) {
274 wxPoint2DDouble clickPointWorld = m_camera->ScreenToWorld(clickPoint);
276 if (!m_elementList.empty()) {
278 newElement = m_elementList.back().get();
279 for (
auto& element : m_elementList) {
281 if (element->Contains(clickPointWorld)) {
283 if (
auto bus =
dynamic_cast<Bus*
>(element.get())) {
289 if (newElement->
AddParent(bus, clickPointWorld)) {
290 ValidateElementsVoltages();
292 showNewElementForm =
true;
293 m_mode = WorkspaceMode::MODE_EDIT;
302 if (
auto line =
dynamic_cast<Line*
>(newElement)) { line->AddPoint(clickPointWorld); }
310 bool clickPickbox =
false;
312 for (
auto& element : m_elementList) {
313 element->ResetPickboxes();
316 element->StartMove(m_camera->ScreenToWorld(clickPoint));
319 if (element->NodeContains(m_camera->ScreenToWorld(clickPoint)) != 0 && element->IsSelected()) {
320 m_mode = WorkspaceMode::MODE_MOVE_NODE;
321 m_disconnectedElement =
true;
324 if (m_hmPlane && m_showHM) {
330 else if (element->Contains(m_camera->ScreenToWorld(clickPoint))) {
331 notUnselectElementList.emplace_back(element.get());
333 if (element->IsSelected()) unselectAll =
false;
335 element->SetSelected();
336 element->ShowPickbox();
339 for (
auto& text : m_textList) {
340 if (text->GetElement() == element.get()) {
341 notUnselectTextList.emplace_back(text.get());
343 text->SetAllowRotation(
false);
344 if (unselectAll) text->SetAltSelectionColour();
349 if (element->PickboxContains(m_camera->ScreenToWorld(clickPoint))) {
350 m_mode = WorkspaceMode::MODE_MOVE_PICKBOX;
354 if (!clickPickbox) { m_mode = WorkspaceMode::MODE_MOVE_ELEMENT; }
356 if (m_hmPlane && m_showHM) {
362 else if (element->SwitchesContains(m_camera->ScreenToWorld(clickPoint))) {
363 element->SetOnline(element->IsOnline() ?
false : true);
364 clickOnSwitch =
true;
369 for (
auto& text : m_textList) {
370 text->
StartMove(m_camera->ScreenToWorld(clickPoint));
372 if (text->
Contains(m_camera->ScreenToWorld(clickPoint))) {
373 notUnselectTextList.emplace_back(text.get());
377 text->SetAltSelectionColour(
false);
378 text->SetAllowRotation();
379 m_mode = WorkspaceMode::MODE_MOVE_ELEMENT;
381 if (m_hmPlane && m_showHM) {
390 if (!event.ControlDown() && unselectAll) {
391 for (
auto& element : m_elementList) {
393 for (
Element* notUnselectElement : notUnselectElementList) {
394 if (notUnselectElement == element.get()) select =
true;
396 element->SetSelected(select);
398 for (
auto& text : m_textList) {
400 for (
auto& notUnselectText : notUnselectTextList) {
401 if (notUnselectText == text.get()) select =
true;
407 if (!foundElement && !clickOnSwitch) {
408 m_mode = WorkspaceMode::MODE_SELECTION_RECT;
409 m_startSelRect = m_camera->ScreenToWorld(clickPoint);
410 if (m_hmPlane && m_showHM) {
418 if (showNewElementForm) {
420 newElement->
ShowForm(
this, newElement);
421 CheckSlackBusDuplication(newElement);
423 if (m_continuousCalc) RunStaticStudies();
426 if (clickOnSwitch && m_continuousCalc) RunStaticStudies();
431void Workspace::OnLeftDoubleClick(wxMouseEvent& event)
433 bool elementEdited =
false;
434 bool clickOnSwitch =
false;
437 for (
auto& element : m_elementList) {
439 if (element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
440 bool elementIsBus =
false;
442 Bus* currentBus =
nullptr;
443 if ((currentBus =
dynamic_cast<Bus*
>(element.get()))) {
445 oldBus = *currentBus;
448 if (element->ShowForm(
this, element.get())) {
449 CheckSlackBusDuplication(element.get());
452 elementEdited =
true;
459 if (oldBus.GetElectricalData().nominalVoltage != currentBus->GetElectricalData().nominalVoltage ||
460 oldBus.GetElectricalData().nominalVoltageUnit !=
461 currentBus->GetElectricalData().nominalVoltageUnit) {
463 std::vector<Element*> childList = element->GetChildList();
464 for (
auto itc = childList.begin(), itcEnd = childList.end(); itc != itcEnd; ++itc) {
466 if (
typeid(*child) ==
typeid(
Line)) {
467 wxMessageDialog msgDialog(
this, _(
"Do you want to change the rated voltage of the path?"),
468 _(
"Warning"), wxYES_NO | wxCENTRE | wxICON_WARNING);
469 if (msgDialog.ShowModal() == wxID_YES)
470 ValidateBusesVoltages(element.get());
472 auto data = currentBus->GetElectricalData();
473 data.nominalVoltage = oldBus.GetElectricalData().nominalVoltage;
474 data.nominalVoltageUnit = oldBus.GetElectricalData().nominalVoltageUnit;
475 currentBus->SetElectricalData(data);
481 ValidateElementsVoltages();
486 else if (element->SwitchesContains(m_camera->ScreenToWorld(event.GetPosition()))) {
487 element->SetOnline(element->IsOnline() ?
false : true);
488 clickOnSwitch =
true;
493 for (
auto& text : m_textList) {
494 if (text->
Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
495 if (text->ShowForm(
this, GetElementList())) SaveCurrentState();
500 UpdateTextElements();
501 if (m_continuousCalc) RunStaticStudies();
503 if (clickOnSwitch && m_continuousCalc) RunStaticStudies();
505 if (redraw) Redraw();
509void Workspace::OnRightClickDown(wxMouseEvent& event)
512 if (m_mode == WorkspaceMode::MODE_EDIT) {
513 for (
auto& element : m_elementList) {
514 if (element->IsSelected()) {
516 if (element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
517 element->ShowPickbox(
false);
519 menu.SetClientData(element.get());
520 if (element->GetContextMenu(menu)) {
522 menu.Bind(wxEVT_COMMAND_MENU_SELECTED, &Workspace::OnPopupClick,
this);
526 if (!menu.GetClientData())
break;
528 element->ResetPickboxes();
533 if (redraw) Redraw();
537void Workspace::OnLeftClickUp(wxMouseEvent& event)
541 bool foundPickbox =
false;
542 bool findNewParent =
false;
543 bool updateVoltages =
false;
544 bool saveCurrentState =
false;
545 auto itnp = m_elementList.begin();
547 for (
auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
550 if (m_mode == WorkspaceMode::MODE_MOVE_PICKBOX) {
552 if (element->IsPickboxShown()) {
553 saveCurrentState =
true;
555 if (
auto bus =
dynamic_cast<Bus*
>(element.get())) {
557 for (
auto child : m_elementList) {
558 for (
auto parent : child->GetParentList()) {
562 m_disconnectedElement =
true;
581 if (m_mode == WorkspaceMode::MODE_SELECTION_RECT) {
582 if (element->Intersects(m_selectionRect)) {
583 element->SetSelected();
585 for (
auto& text : m_textList) {
586 if (text->GetElement() == element.get()) {
588 text->SetAltSelectionColour(
false);
589 text->SetAllowRotation();
597 else if (m_mode == WorkspaceMode::MODE_MOVE_NODE) {
598 if (element->IsSelected()) {
599 saveCurrentState =
true;
600 for (
auto parent : m_elementList) {
601 if (
auto bus =
dynamic_cast<Bus*
>(parent.get())) {
602 if (element->SetNodeParent(bus)) {
603 parent->AddChild(element.get());
604 findNewParent =
true;
606 element->ResetNodes();
620 if (element->PickboxContains(m_camera->ScreenToWorld(event.GetPosition()))) {
624 element->ShowPickbox(
false);
625 element->ResetPickboxes();
631 for (
auto& text : m_textList) {
632 if (m_mode == WorkspaceMode::MODE_SELECTION_RECT) {
635 text->SetAltSelectionColour(
false);
636 text->SetAllowRotation();
646 if (m_mode == WorkspaceMode::MODE_MOVE_ELEMENT) saveCurrentState =
true;
649 std::rotate(itnp, itnp + 1, m_elementList.end());
650 updateVoltages =
true;
652 if (!foundPickbox) { SetCursor(wxCURSOR_ARROW); }
654 if (m_mode != WorkspaceMode::MODE_INSERT) { m_mode = WorkspaceMode::MODE_EDIT; }
656 if (updateVoltages) { ValidateElementsVoltages(); }
658 if (saveCurrentState) SaveCurrentState();
660 if (m_continuousCalc && m_disconnectedElement) {
661 m_disconnectedElement =
false;
665 m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
667 if (m_hmPlane && m_showHM) {
668 m_showHMTimer =
true;
669 m_timerHeatMap->Start();
676void Workspace::OnMouseMotion(wxMouseEvent& event)
680 case WorkspaceMode::MODE_INSERT: {
681 auto& newElement = m_elementList.back();
682 newElement->
SetPosition(m_camera->ScreenToWorld(event.GetPosition()));
686 case WorkspaceMode::MODE_INSERT_TEXT: {
687 auto& newText = m_textList.back();
688 newText->SetPosition(m_camera->ScreenToWorld(event.GetPosition()));
692 case WorkspaceMode::MODE_DRAG:
693 case WorkspaceMode::MODE_DRAG_INSERT:
694 case WorkspaceMode::MODE_DRAG_INSERT_TEXT:
695 case WorkspaceMode::MODE_DRAG_PASTE: {
696 m_camera->SetTranslation(event.GetPosition());
700 case WorkspaceMode::MODE_EDIT: {
701 bool foundPickbox =
false;
702 for (
auto& element : m_elementList) {
703 if (element->IsSelected()) {
705 if (element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
706 element->ShowPickbox();
710 if (element->PickboxContains(m_camera->ScreenToWorld(event.GetPosition()))) {
712 SetCursor(element->GetBestPickboxCursor());
714 else if (!foundPickbox) {
715 SetCursor(wxCURSOR_ARROW);
716 element->ResetPickboxes();
719 else if (!foundPickbox) {
720 if (element->IsPickboxShown()) redraw =
true;
722 element->ShowPickbox(
false);
723 element->ResetPickboxes();
724 SetCursor(wxCURSOR_ARROW);
730 case WorkspaceMode::MODE_MOVE_NODE: {
731 for (
auto& element : m_elementList) {
732 if (element->IsSelected()) {
733 element->MoveNode(
nullptr, m_camera->ScreenToWorld(event.GetPosition()));
739 case WorkspaceMode::MODE_MOVE_PICKBOX: {
740 for (
auto& element : m_elementList) {
741 if (element->IsSelected()) {
742 element->MovePickbox(m_camera->ScreenToWorld(event.GetPosition()));
746 if (m_hmPlane && m_showHM) {
751 case WorkspaceMode::MODE_MOVE_ELEMENT:
752 case WorkspaceMode::MODE_PASTE: {
753 for (
auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
755 if (element->IsSelected()) {
756 element->Move(m_camera->ScreenToWorld(event.GetPosition()));
758 std::vector<Element*> childList = element->GetChildList();
759 for (
auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
760 (*it)->MoveNode(element.get(), m_camera->ScreenToWorld(event.GetPosition()));
766 for (
auto& text : m_textList) {
768 text->
Move(m_camera->ScreenToWorld(event.GetPosition()));
772 if (m_hmPlane && m_showHM) {
777 case WorkspaceMode::MODE_SELECTION_RECT: {
778 wxPoint2DDouble currentPos = m_camera->ScreenToWorld(event.GetPosition());
780 if (currentPos.m_x < m_startSelRect.m_x) {
782 w = m_startSelRect.m_x - currentPos.m_x;
785 x = m_startSelRect.m_x;
786 w = currentPos.m_x - m_startSelRect.m_x;
788 if (currentPos.m_y < m_startSelRect.m_y) {
790 h = m_startSelRect.m_y - currentPos.m_y;
793 y = m_startSelRect.m_y;
794 h = currentPos.m_y - m_startSelRect.m_y;
797 m_selectionRect = wxRect2DDouble(x, y, w, h);
805 m_camera->UpdateMousePosition(event.GetPosition());
811void Workspace::OnMiddleDown(wxMouseEvent& event)
815 case WorkspaceMode::MODE_INSERT: {
816 m_mode = WorkspaceMode::MODE_DRAG_INSERT;
818 case WorkspaceMode::MODE_INSERT_TEXT: {
819 m_mode = WorkspaceMode::MODE_DRAG_INSERT_TEXT;
821 case WorkspaceMode::MODE_PASTE: {
822 m_mode = WorkspaceMode::MODE_DRAG_PASTE;
825 m_mode = WorkspaceMode::MODE_DRAG;
828 m_camera->StartTranslation(m_camera->ScreenToWorld(event.GetPosition()));
831 if (m_hmPlane && m_showHM) {
838void Workspace::OnMiddleUp(wxMouseEvent& event)
841 case WorkspaceMode::MODE_DRAG_INSERT: {
842 m_mode = WorkspaceMode::MODE_INSERT;
844 case WorkspaceMode::MODE_DRAG_INSERT_TEXT: {
845 m_mode = WorkspaceMode::MODE_INSERT_TEXT;
847 case WorkspaceMode::MODE_DRAG_PASTE: {
848 m_mode = WorkspaceMode::MODE_PASTE;
850 case WorkspaceMode::MODE_INSERT:
851 case WorkspaceMode::MODE_INSERT_TEXT:
852 case WorkspaceMode::MODE_PASTE: {
856 m_mode = WorkspaceMode::MODE_EDIT;
861 if (m_hmPlane && m_showHM) {
869void Workspace::OnScroll(wxMouseEvent& event)
871 if (event.GetWheelRotation() > 0)
872 m_camera->SetScale(event.GetPosition(), +0.05);
874 m_camera->SetScale(event.GetPosition(), -0.05);
876 if (m_hmPlane && m_showHM) {
878 m_showHMTimer =
true;
879 m_timerHeatMap->Start();
886void Workspace::OnKeyDown(wxKeyEvent& event)
888 bool insertingElement =
false;
889 if (m_mode == WorkspaceMode::MODE_INSERT || m_mode == WorkspaceMode::MODE_INSERT_TEXT) insertingElement =
true;
891 char key =
event.GetUnicodeKey();
892 if (key != WXK_NONE) {
896 if (m_mode == WorkspaceMode::MODE_INSERT) {
898 auto elementToDelete = m_elementList.back();
901 for (
auto& element : m_elementList) {
902 element->RemoveChild(elementToDelete.get());
905 m_elementList.pop_back();
906 m_mode = WorkspaceMode::MODE_EDIT;
909 else if (m_mode == WorkspaceMode::MODE_INSERT_TEXT) {
910 m_textList.pop_back();
911 m_mode = WorkspaceMode::MODE_EDIT;
917 DeleteSelectedElements();
920 if (!insertingElement) {
922 auto newText = std::make_shared<Text>(
923 m_camera->ScreenToWorld(event.GetPosition()),
924 m_properties->GetGeneralPropertiesData().labelFont,
925 m_properties->GetGeneralPropertiesData().labelFontSize);
926 m_textList.push_back(newText);
927 m_mode = WorkspaceMode::MODE_INSERT_TEXT;
928 m_statusBar->SetStatusText(_(
"Insert Text: Click to insert, ESC to cancel."));
929 if (m_hmPlane && m_showHM) {
936 if (event.GetModifiers() == wxMOD_SHIFT) { Fit(); }
940 RotateSelectedElements(event.GetModifiers() != wxMOD_SHIFT);
944 if (!insertingElement) {
945 auto newBus = std::make_shared<Bus>(m_camera->ScreenToWorld(event.GetPosition()),
946 wxString::Format(_(
"Bus %d"), GetElementNumber(ID_BUS)));
947 IncrementElementNumber(ID_BUS);
948 m_elementList.push_back(newBus);
949 m_mode = WorkspaceMode::MODE_INSERT;
950 m_statusBar->SetStatusText(_(
"Insert Bus: Click to insert, ESC to cancel."));
951 if (m_hmPlane && m_showHM) {
958 if (!insertingElement) {
959 if (!event.ControlDown() && event.ShiftDown()) {
960 auto newLoad = std::make_shared<Load>(wxString::Format(_(
"Load %d"), GetElementNumber(ID_LOAD)));
961 IncrementElementNumber(ID_LOAD);
962 m_elementList.push_back(newLoad);
963 m_mode = WorkspaceMode::MODE_INSERT;
964 m_statusBar->SetStatusText(_(
"Insert Load: Click on a bus, ESC to cancel."));
966 else if (!event.ControlDown() && !event.ShiftDown()) {
967 auto newLine = std::make_shared<Line>(wxString::Format(_(
"Line %d"), GetElementNumber(ID_LINE)));
968 IncrementElementNumber(ID_LINE);
969 m_elementList.push_back(newLine);
970 m_mode = WorkspaceMode::MODE_INSERT;
971 m_statusBar->SetStatusText(_(
"Insert Line: Click on two buses, ESC to cancel."));
973 if (m_hmPlane && m_showHM) {
982 if (!insertingElement) {
983 auto newTransformer = std::make_shared<Transformer>(wxString::Format(_(
"Transformer %d"), GetElementNumber(ID_TRANSFORMER)));
984 IncrementElementNumber(ID_TRANSFORMER);
985 m_elementList.push_back(newTransformer);
986 m_mode = WorkspaceMode::MODE_INSERT;
987 m_statusBar->SetStatusText(_(
"Insert Transformer: Click on two buses, ESC to cancel."));
988 if (m_hmPlane && m_showHM) {
996 if (!insertingElement) {
997 auto newGenerator = std::make_shared<SyncGenerator>(wxString::Format(_(
"Generator %d"), GetElementNumber(ID_SYNCGENERATOR)));
998 IncrementElementNumber(ID_SYNCGENERATOR);
999 m_elementList.push_back(newGenerator);
1000 m_mode = WorkspaceMode::MODE_INSERT;
1001 m_statusBar->SetStatusText(_(
"Insert Generator: Click on a bus, ESC to cancel."));
1002 if (m_hmPlane && m_showHM) {
1009 if (!insertingElement) {
1010 if (event.GetModifiers() == wxMOD_SHIFT) {
1011 auto newInductor = std::make_shared<Inductor>(wxString::Format(_(
"Inductor %d"), GetElementNumber(ID_INDUCTOR)));
1012 IncrementElementNumber(ID_INDUCTOR);
1013 m_elementList.push_back(newInductor);
1014 m_mode = WorkspaceMode::MODE_INSERT;
1015 m_statusBar->SetStatusText(_(
"Insert Inductor: Click on a bus, ESC to cancel."));
1019 auto newIndMotor = std::make_shared<IndMotor>(wxString::Format(_(
"Induction motor %d"), GetElementNumber(ID_INDMOTOR)));
1020 IncrementElementNumber(ID_INDMOTOR);
1021 m_elementList.push_back(newIndMotor);
1022 m_mode = WorkspaceMode::MODE_INSERT;
1023 m_statusBar->SetStatusText(_(
"Insert Induction Motor: Click on a bus, ESC to cancel."));
1025 if (m_hmPlane && m_showHM) {
1033 if (!insertingElement) {
1034 auto newSyncCondenser = std::make_shared<SyncMotor>(wxString::Format(_(
"Synchronous condenser %d"), GetElementNumber(ID_SYNCMOTOR)));
1035 IncrementElementNumber(ID_SYNCMOTOR);
1036 m_elementList.push_back(newSyncCondenser);
1037 m_mode = WorkspaceMode::MODE_INSERT;
1038 m_statusBar->SetStatusText(_(
"Insert Synchronous Condenser: Click on a bus, ESC to cancel."));
1039 if (m_hmPlane && m_showHM) {
1046 if (!insertingElement) {
1047 if (event.GetModifiers() == wxMOD_SHIFT) {
1048 auto newCapacitor = std::make_shared<Capacitor>(wxString::Format(_(
"Capacitor %d"), GetElementNumber(ID_CAPACITOR)));
1049 IncrementElementNumber(ID_CAPACITOR);
1050 m_elementList.push_back(newCapacitor);
1051 m_mode = WorkspaceMode::MODE_INSERT;
1052 m_statusBar->SetStatusText(_(
"Insert Capacitor: Click on a bus, ESC to cancel."));
1053 if (m_hmPlane && m_showHM) {
1058 else if (event.GetModifiers() == wxMOD_CONTROL) {
1064 if (!insertingElement) {
1065 if (event.ShiftDown() && event.ControlDown()) {
1075 else if (event.GetModifiers() == wxMOD_SHIFT) {
1076 auto newHarmCurrent = std::make_shared<HarmCurrent>(
1077 wxString::Format(_(
"Harmonic Current %d"), GetElementNumber(ID_HARMCURRENT)));
1078 IncrementElementNumber(ID_HARMCURRENT);
1079 m_elementList.push_back(newHarmCurrent);
1080 m_mode = WorkspaceMode::MODE_INSERT;
1081 m_statusBar->SetStatusText(
1082 _(
"Insert Harmonic Current Source: Click on a bus, ESC to cancel."));
1084 if (m_hmPlane && m_showHM) {
1091 if (!insertingElement) {
1092 if (event.GetModifiers() == wxMOD_CONTROL) { Paste(); }
1096 if (!insertingElement) {
1097 if (event.GetModifiers() == wxMOD_CONTROL) {
1101 if (GetSavedPath().IsOk()) {
1102 fileHandling.SaveProject(GetSavedPath());
1105 wxFileDialog saveFileDialog(
this, _(
"Save PSP file"),
"",
"",
"PSP files (*.psp)|*.psp",
1106 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
1107 if (saveFileDialog.ShowModal() == wxID_CANCEL)
return;
1109 fileHandling.SaveProject(saveFileDialog.GetPath());
1110 wxFileName fileName(saveFileDialog.GetPath());
1111 SetName(fileName.GetName());
1112 if (m_auiNotebook) m_auiNotebook->SetPageText(m_auiNotebook->GetPageIndex(
this), GetName());
1113 SetSavedPath(fileName);
1119 if (!insertingElement) {
1120 if (event.ControlDown() && !event.ShiftDown()) { SetPreviousState(); }
1121 if (event.ControlDown() && event.ShiftDown()) { SetNextState(); }
1125 if (!insertingElement) {
1126 if (event.GetModifiers() == wxMOD_CONTROL) { SetNextState(); }
1130 if (!insertingElement) {
1131 if (event.GetModifiers() == wxMOD_SHIFT) {
1133 if (!insertingElement) {
1134 auto newEMTElement = std::make_shared<EMTElement>(wxString::Format(_(
"Electromagnetic Element %d"), GetElementNumber(ID_EMTELEMENT)));
1135 IncrementElementNumber(ID_EMTELEMENT);
1136 m_elementList.push_back(newEMTElement);
1137 m_mode = WorkspaceMode::MODE_INSERT;
1138 m_statusBar->SetStatusText(_(
"Insert Electromagnetic Transient Element: Click on a bus, ESC to cancel."));
1139 if (m_hmPlane && m_showHM) {
1148#ifdef SHOW_DEBUG_PANEL
1150 if (event.GetModifiers() == wxMOD_CONTROL) {
1152 m_debugFrame->SetFocus();
1167void Workspace::UpdateStatusBar()
1170 case WorkspaceMode::MODE_DRAG: {
1171 m_statusBar->SetStatusText(_(
"MODE: DRAG"), 1);
1174 case WorkspaceMode::MODE_PASTE:
1175 case WorkspaceMode::MODE_DRAG_PASTE: {
1176 m_statusBar->SetStatusText(_(
"MODE: PASTE"), 1);
1179 case WorkspaceMode::MODE_INSERT:
1180 case WorkspaceMode::MODE_INSERT_TEXT:
1181 case WorkspaceMode::MODE_DRAG_INSERT:
1182 case WorkspaceMode::MODE_DRAG_INSERT_TEXT: {
1183 m_statusBar->SetStatusText(_(
"MODE: INSERT"), 1);
1186 case WorkspaceMode::MODE_MOVE_ELEMENT:
1187 case WorkspaceMode::MODE_MOVE_PICKBOX:
1188 case WorkspaceMode::MODE_MOVE_NODE:
1189 case WorkspaceMode::MODE_SELECTION_RECT:
1190 case WorkspaceMode::MODE_EDIT: {
1191 if (m_oldStatusMode != m_mode)
1192 m_statusBar->SetStatusText(wxT(
""));
1193 m_statusBar->SetStatusText(_(
"MODE: EDIT"), 1);
1197 m_statusBar->SetStatusText(wxString::Format(_(
"ZOOM: %d%%"), (
int)(m_camera->GetScale() * 100.0)), 2);
1198 m_statusBar->SetStatusText(
1199 wxString::Format(wxT(
"X: %.1f Y: %.1f"), m_camera->GetMousePosition().m_x, m_camera->GetMousePosition().m_y),
1201 m_oldStatusMode = m_mode;
1204int Workspace::GetElementNumberFromList(
Element* element)
1207 for (
auto& elementFromList : m_elementList) {
1208 if (element->GetElementType() == elementFromList->GetElementType()) {
1209 if (element == elementFromList.get())
return elementNum;
1216void Workspace::GetStateListsCopy(
const std::vector< std::shared_ptr<PowerElement> >& elementsList,
1217 const std::vector< std::shared_ptr<Text> >& textList,
1218 std::vector< std::shared_ptr<PowerElement> >& elementsListCopy,
1219 std::vector< std::shared_ptr<Text> >& textListCopy)
1224 elementsListCopy.clear();
1225 textListCopy.clear();
1227 std::map<Element*, Element*> elementMap;
1229 for (
auto& element : elementsList) {
1231 elementsListCopy.emplace_back(copyElement);
1232 elementMap[element.get()] = copyElement;
1235 for (
auto& copyElement : elementsListCopy) {
1238 for (
Element* parent : copyElement->GetParentList()) {
1239 auto it = elementMap.find(parent);
1241 if (it != elementMap.end())
1242 copyElement->SetParent(it->second, i);
1248 for (
Element* child : copyElement->GetChildList()) {
1249 auto it = elementMap.find(child);
1251 if (it != elementMap.end())
1252 copyElement->SetChild(it->second, i);
1258 for (
const auto& text : textList) {
1259 auto copyText =
static_cast<Text*
>(text->
GetCopy());
1261 auto it = elementMap.find(copyText->GetElement());
1263 if (it != elementMap.end())
1264 copyText->SetElement(it->second);
1266 copyText->SetElement(
nullptr);
1267 textListCopy.emplace_back(copyText);
1271void Workspace::UpdateHeatMap()
1273 if (m_hmPlane && m_showHM) {
1276 wxRect2DDouble screenRect(-100, -100, m_width + 200.0, m_height + 200.0);
1279 std::vector<Bus*> busList;
1280 float minVoltage, maxVoltage;
1281 if (m_hmAutomaticLabel) {
1286 minVoltage = m_hmPlane->GetMinLimit();
1287 maxVoltage = m_hmPlane->GetMaxLimit();
1290 for (
auto& element : m_elementList) {
1291 if (
Bus* bus =
dynamic_cast<Bus*
>(element.get())) {
1292 if (m_hmAutomaticLabel) {
1293 const float voltage = std::abs(bus->GetElectricalData().voltage);
1294 if (minVoltage > voltage) minVoltage = voltage;
1295 if (maxVoltage < voltage) maxVoltage = voltage;
1297 busList.push_back(bus);
1300 if (m_hmAutomaticLabel) {
1301 m_hmPlane->SetLabelLimits(minVoltage, maxVoltage);
1304 for (
Bus* bus : busList) {
1305 const float voltage = std::abs(bus->GetElectricalData().voltage);
1306 float depth = 2.0f * (voltage - (maxVoltage + minVoltage) / 2.0f) / (maxVoltage - minVoltage);
1307 if (depth < -1.0) depth = -1.0;
1308 if (depth > 1.0) depth = 1.0;
1310 wxRect2DDouble rect = bus->GetRect();
1311 rect = wxRect2DDouble(
1312 (rect.m_x - 100.0f) * m_camera->GetScale() + m_camera->GetTranslation().m_x * m_camera->GetScale(),
1313 (rect.m_y - 50.0f) * m_camera->GetScale() + m_camera->GetTranslation().m_y * m_camera->GetScale(),
1314 (rect.m_width + 200.0f) * m_camera->GetScale(),
1315 (rect.m_height + 100.0f) * m_camera->GetScale());
1317 if (screenRect.Contains(rect))
1318 m_hmPlane->SetRectSlope(rect, M_PI *
static_cast<float>(bus->GetAngle()) / 180.0f, depth);
1324 int iterations = std::lround(10 * std::pow(m_camera->GetScale(), 2));
1327 if (iterations < 1) iterations = 1;
1328 m_hmPlane->SmoothPlane(iterations);
1332void Workspace::OnPopupClick(wxCommandEvent& event)
1334 bool redrawHM =
false;
1336 wxMenu* menu =
static_cast<wxMenu*
>(
event.GetEventObject());
1338 int eventID =
event.GetId();
1341 if (element->
ShowForm(
this, element)) {
1342 CheckSlackBusDuplication(element);
1343 UpdateTextElements();
1348 Line* line =
static_cast<Line*
>(element);
1349 line->AddNode(m_camera->GetMousePosition());
1354 Line* line =
static_cast<Line*
>(element);
1355 line->RemoveNode(m_camera->GetMousePosition());
1361 for (
auto& iElement : m_elementList) {
1363 for (
int i = 0; i < (int)iElement->GetParentList().size(); i++) {
1365 if (parent == element) { iElement->RotateNode(parent); }
1374 for (
auto& iElement : m_elementList) {
1376 for (
int i = 0; i < (int)iElement->GetParentList().size(); i++) {
1378 if (parent == element) { iElement->RotateNode(parent,
false); }
1425 std::vector<Element*> childList = element->
GetChildList();
1426 for (
auto child : childList) {
1433 std::vector<Element*> parentList = element->
GetParentList();
1434 for (
auto parent : parentList) {
1439 std::erase_if(m_textList, [&](
const auto& text) {
1440 return text->GetElement() == element;
1443 std::erase_if(m_elementList, [&](
const auto& delElement) {
1444 return delElement.get() == element;
1447 menu->SetClientData(
nullptr);
1451 if (InsertTextElement(eventID, element)) {
1452 UpdateTextElements();
1457 if (redrawHM && m_hmPlane && m_showHM) {
1459 m_showHMTimer =
true;
1460 m_timerHeatMap->Start();
1464void Workspace::RotateSelectedElements(
bool clockwise)
1466 bool saveCurrrentState =
false;
1467 for (
auto& element : m_elementList) {
1469 for (
int i = 0; i < (int)element->
GetParentList().size(); i++) {
1476 element->
StartMove(m_camera->GetMousePosition());
1481 saveCurrrentState =
true;
1482 element->
Rotate(clockwise);
1483 element->
StartMove(m_camera->GetMousePosition());
1488 for (
auto& text : m_textList) {
1490 saveCurrrentState =
true;
1492 text->
StartMove(m_camera->GetMousePosition());
1495 if (saveCurrrentState) SaveCurrentState();
1497 if (m_hmPlane && m_showHM) {
1499 m_showHMTimer =
true;
1500 m_timerHeatMap->Start();
1505void Workspace::DeleteSelectedElements()
1508 for (
auto it = m_elementList.begin(); it != m_elementList.end();) {
1513 std::vector<Element*> childList = element->
GetChildList();
1514 for (
auto itc = childList.begin(), itEnd = childList.end(); itc != itEnd; ++itc) {
1521 std::vector<Element*> parentList = element->
GetParentList();
1522 for (
auto itp = parentList.begin(), itEnd = parentList.end(); itp != itEnd; ++itp) {
1537 std::erase_if(m_textList, [&](
const auto& text) {
1538 return text->GetElement() == element;
1541 it = m_elementList.erase(it);
1558 std::erase_if(m_textList, [](
const auto& text) {
1562 if (m_hmPlane && m_showHM) {
1564 m_showHMTimer =
true;
1565 m_timerHeatMap->Start();
1571bool Workspace::GetElementsCorners(wxPoint2DDouble& leftUpCorner,
1572 wxPoint2DDouble& rightDownCorner,
1573 std::vector<Element*> elementList)
1575 if (elementList.size() == 0)
return false;
1577 elementList[0]->CalculateBoundaries(leftUpCorner, rightDownCorner);
1579 for (
auto it = elementList.begin() + 1, itEnd = elementList.end(); it != itEnd; it++) {
1581 wxPoint2DDouble leftUp;
1582 wxPoint2DDouble rightDown;
1584 if (leftUp.m_x < leftUpCorner.m_x) leftUpCorner.m_x = leftUp.m_x;
1585 if (leftUp.m_y < leftUpCorner.m_y) leftUpCorner.m_y = leftUp.m_y;
1586 if (rightDown.m_x > rightDownCorner.m_x) rightDownCorner.m_x = rightDown.m_x;
1587 if (rightDown.m_y > rightDownCorner.m_y) rightDownCorner.m_y = rightDown.m_y;
1592void Workspace::Fit()
1594 wxPoint2DDouble leftUpCorner(0, 0);
1595 wxPoint2DDouble rightDownCorner(0, 0);
1596 std::vector<Element*> elementList = GetElementList();
1597 for (
const auto& text : m_textList) { elementList.push_back(text.get()); }
1599 if (!GetElementsCorners(leftUpCorner, rightDownCorner, elementList))
return;
1600 wxPoint2DDouble middleCoords = (leftUpCorner + rightDownCorner) / 2.0;
1604 GetSize(&width, &height);
1606 double scaleX = double(width) / (rightDownCorner.m_x - leftUpCorner.m_x);
1607 double scaleY = double(height) / (rightDownCorner.m_y - leftUpCorner.m_y);
1609 double scale = scaleX < scaleY ? scaleX : scaleY;
1610 if (scale > m_camera->GetZoomMax()) scale = m_camera->GetZoomMax();
1611 if (scale < m_camera->GetZoomMin()) scale = m_camera->GetZoomMin();
1613 m_camera->SetScale(scale);
1615 m_camera->StartTranslation(middleCoords);
1616 m_camera->SetTranslation(wxPoint2DDouble(width / 2, height / 2));
1618 if (m_hmPlane && m_showHM) {
1625bool Workspace::InsertTextElement(
int textID,
Element* parentElement,
ElectricalUnit unit,
int precision)
1629 if (FindTextElement(parentElement, DATA_NAME))
return false;
1631 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(40, -30), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1632 newText->SetElement(parentElement);
1633 newText->SetDataType(DATA_NAME);
1634 newText->SetElementTypeText(parentElement->GetElementType());
1635 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1637 m_textList.push_back(newText);
1639 case ID_TXT_VOLTAGE: {
1640 if (FindTextElement(parentElement, DATA_VOLTAGE))
return false;
1642 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(40, 15), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1643 newText->SetElement(parentElement);
1644 newText->SetDataType(DATA_VOLTAGE);
1645 if (unit == ElectricalUnit::UNIT_NONE)
1648 newText->SetUnit(unit);
1649 newText->SetDecimalPlaces(precision);
1650 newText->SetElementTypeText(parentElement->GetElementType());
1651 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1653 m_textList.emplace_back(newText);
1655 case ID_TXT_ANGLE: {
1656 if (FindTextElement(parentElement, DATA_ANGLE))
return false;
1658 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(40, 30), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1659 newText->SetElement(parentElement);
1660 newText->SetDataType(DATA_ANGLE);
1661 if (unit == ElectricalUnit::UNIT_NONE)
1664 newText->SetUnit(unit);
1665 newText->SetDecimalPlaces(precision);
1666 newText->SetElementTypeText(parentElement->GetElementType());
1667 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1669 m_textList.emplace_back(newText);
1671 case ID_TXT_FAULTCURRENT: {
1672 if (FindTextElement(parentElement, DATA_SC_CURRENT))
return false;
1674 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(-70, 30), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1675 newText->SetElement(parentElement);
1676 newText->SetDataType(DATA_SC_CURRENT);
1677 if (unit == ElectricalUnit::UNIT_NONE)
1680 newText->SetUnit(unit);
1681 newText->SetDecimalPlaces(precision);
1682 newText->SetElementTypeText(parentElement->GetElementType());
1683 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1685 m_textList.emplace_back(newText);
1687 case ID_TXT_FAULTVOLTAGE: {
1688 if (FindTextElement(parentElement, DATA_SC_VOLTAGE))
return false;
1690 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(-70, 75), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1691 newText->SetElement(parentElement);
1692 newText->SetDataType(DATA_SC_VOLTAGE);
1693 if (unit == ElectricalUnit::UNIT_NONE)
1696 newText->SetUnit(unit);
1697 newText->SetDecimalPlaces(precision);
1698 newText->SetElementTypeText(parentElement->GetElementType());
1699 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1701 m_textList.emplace_back(newText);
1704 if (FindTextElement(parentElement, DATA_SC_POWER))
return false;
1705 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(-50, -30), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1706 newText->SetElement(parentElement);
1707 newText->SetDataType(DATA_SC_POWER);
1709 if (unit == ElectricalUnit::UNIT_NONE)
1712 newText->SetUnit(unit);
1713 newText->SetDecimalPlaces(precision);
1714 newText->SetElementTypeText(parentElement->GetElementType());
1715 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1717 m_textList.emplace_back(newText);
1720 if (FindTextElement(parentElement, DATA_PQ_THD))
return false;
1721 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(-50, -15), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1722 newText->SetElement(parentElement);
1723 newText->SetDataType(DATA_PQ_THD);
1724 newText->SetDecimalPlaces(precision);
1725 newText->SetElementTypeText(parentElement->GetElementType());
1726 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1728 m_textList.emplace_back(newText);
1730 case ID_TXT_ACTIVE_POWER: {
1731 if (FindTextElement(parentElement, DATA_ACTIVE_POWER))
return false;
1732 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(0, 35), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1733 newText->SetElement(parentElement);
1734 newText->SetDataType(DATA_ACTIVE_POWER);
1735 if (unit == ElectricalUnit::UNIT_NONE)
1738 newText->SetUnit(unit);
1739 newText->SetDecimalPlaces(precision);
1740 newText->SetElementTypeText(parentElement->GetElementType());
1741 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1743 m_textList.emplace_back(newText);
1745 case ID_TXT_REACTIVE_POWER: {
1746 if (FindTextElement(parentElement, DATA_REACTIVE_POWER))
return false;
1747 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(0, 50), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1748 newText->SetElement(parentElement);
1749 newText->SetDataType(DATA_REACTIVE_POWER);
1750 if (unit == ElectricalUnit::UNIT_NONE)
1753 newText->SetUnit(unit);
1754 newText->SetDecimalPlaces(precision);
1755 newText->SetElementTypeText(parentElement->GetElementType());
1756 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1758 m_textList.emplace_back(newText);
1760 case ID_TXT_BRANCH_ACTIVE_POWER_1_2:
1761 case ID_TXT_BRANCH_ACTIVE_POWER_2_1: {
1762 if (FindTextElement(parentElement, DATA_PF_ACTIVE))
return false;
1763 wxPoint2DDouble position(0.0, -10.0);
1764 if (textID == ID_TXT_BRANCH_ACTIVE_POWER_1_2)
1769 auto newText = std::make_shared<Text>(position, m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1770 newText->SetElement(parentElement);
1771 newText->SetDataType(DATA_PF_ACTIVE);
1772 if (unit == ElectricalUnit::UNIT_NONE)
1775 newText->SetUnit(unit);
1776 newText->SetDecimalPlaces(precision);
1777 newText->SetElementTypeText(parentElement->GetElementType());
1778 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1779 if (textID == ID_TXT_BRANCH_ACTIVE_POWER_2_1)
1780 newText->SetDirection(1);
1782 m_textList.emplace_back(newText);
1784 case ID_TXT_BRANCH_REACTIVE_POWER_1_2:
1785 case ID_TXT_BRANCH_REACTIVE_POWER_2_1: {
1786 if (FindTextElement(parentElement, DATA_PF_REACTIVE))
return false;
1787 wxPoint2DDouble position(0.0, 10.0);
1788 if (textID == ID_TXT_BRANCH_REACTIVE_POWER_1_2)
1793 auto newText = std::make_shared<Text>(position, m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1794 newText->SetElement(parentElement);
1795 newText->SetDataType(DATA_PF_REACTIVE);
1796 if (unit == ElectricalUnit::UNIT_NONE)
1799 newText->SetUnit(unit);
1800 newText->SetDecimalPlaces(precision);
1801 newText->SetElementTypeText(parentElement->GetElementType());
1802 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1803 if (textID == ID_TXT_BRANCH_REACTIVE_POWER_2_1)
1804 newText->SetDirection(1);
1806 m_textList.emplace_back(newText);
1808 case ID_TXT_BRANCH_LOSSES: {
1809 if (FindTextElement(parentElement, DATA_PF_LOSSES))
return false;
1811 auto newText = std::make_shared<Text>(position, m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1812 newText->SetElement(parentElement);
1813 newText->SetDataType(DATA_PF_LOSSES);
1814 if (unit == ElectricalUnit::UNIT_NONE)
1817 newText->SetUnit(unit);
1818 newText->SetDecimalPlaces(precision);
1819 newText->SetElementTypeText(parentElement->GetElementType());
1820 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1822 m_textList.emplace_back(newText);
1824 case ID_TXT_BRANCH_CURRENT_1_2:
1825 case ID_TXT_BRANCH_CURRENT_2_1: {
1826 if (FindTextElement(parentElement, DATA_PF_CURRENT))
return false;
1827 wxPoint2DDouble position(0.0, 10.0);
1828 if (textID == ID_TXT_BRANCH_CURRENT_1_2)
1833 auto newText = std::make_shared<Text>(position, m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1834 newText->SetElement(parentElement);
1835 newText->SetDataType(DATA_PF_CURRENT);
1836 if (unit == ElectricalUnit::UNIT_NONE)
1839 newText->SetUnit(unit);
1840 newText->SetDecimalPlaces(precision);
1841 newText->SetElementTypeText(parentElement->GetElementType());
1842 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1843 if (textID == ID_TXT_BRANCH_CURRENT_2_1)
1844 newText->SetDirection(1);
1846 m_textList.emplace_back(newText);
1848 case ID_TXT_BRANCH_FAULT_CURRENT_1_2:
1849 case ID_TXT_BRANCH_FAULT_CURRENT_2_1: {
1850 if (FindTextElement(parentElement, DATA_SC_CURRENT))
return false;
1851 wxPoint2DDouble position(0.0, 25.0);
1852 if (textID == ID_TXT_BRANCH_FAULT_CURRENT_1_2)
1857 auto newText = std::make_shared<Text>(position, m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1858 newText->SetElement(parentElement);
1859 newText->SetDataType(DATA_SC_CURRENT);
1860 if (unit == ElectricalUnit::UNIT_NONE)
1863 newText->SetUnit(unit);
1864 newText->SetDecimalPlaces(precision);
1865 newText->SetElementTypeText(parentElement->GetElementType());
1866 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1867 if (textID == ID_TXT_BRANCH_FAULT_CURRENT_2_1)
1868 newText->SetDirection(1);
1870 m_textList.emplace_back(newText);
1879Element* Workspace::FindTextElement(
Element* parentElement,
int dataType)
1881 for (
auto& text : m_textList) {
1882 if (text->GetElement() == parentElement && text->GetDataType() == dataType)
1888void Workspace::RemoveAllTextElements()
1897void Workspace::CheckSlackBusDuplication(
Element* newSlackBus)
1899 Bus* newBus =
dynamic_cast<Bus*
>(newSlackBus);
1901 if (!newBus->GetElectricalData().slackBus)
return;
1903 for (
auto& element : m_elementList) {
1904 Bus* bus =
dynamic_cast<Bus*
>(element.get());
1906 if (bus->GetElectricalData().slackBus && bus != newSlackBus) {
1907 wxMessageDialog msgDialog(
this,
1908 wxString::Format(_(
"The system already has %s as the slack bus.\nDo you want to set %s as the new slack bus?"), bus->GetElectricalData().name, newBus->GetElectricalData().name),
1909 _(
"Warning"), wxYES_NO | wxCENTRE | wxICON_WARNING);
1910 if (msgDialog.ShowModal() == wxID_YES) {
1911 auto data = bus->GetElectricalData();
1912 data.slackBus =
false;
1913 bus->SetElectricalData(data);
1917 auto data = newBus->GetElectricalData();
1918 data.slackBus =
false;
1919 newBus->SetElectricalData(data);
1927void Workspace::ValidateBusesVoltages(
Element* initialBus)
1929 double nominalVoltage =
static_cast<Bus*
>(initialBus)->GetElectricalData().nominalVoltage;
1930 ElectricalUnit nominalVoltageUnit =
static_cast<Bus*
>(initialBus)->GetElectricalData().nominalVoltageUnit;
1932 for (
auto it = m_elementList.begin(); it != m_elementList.end(); it++) {
1935 if (
auto line =
dynamic_cast<Line*
>(child)) {
1940 if (data1.nominalVoltage != data2.nominalVoltage ||
1941 data1.nominalVoltageUnit != data2.nominalVoltageUnit) {
1942 data1.nominalVoltage = nominalVoltage;
1943 data2.nominalVoltage = nominalVoltage;
1944 data1.nominalVoltageUnit = nominalVoltageUnit;
1945 data2.nominalVoltageUnit = nominalVoltageUnit;
1950 it = m_elementList.begin();
1959void Workspace::ValidateElementsVoltages()
1961 for (
auto& child : m_elementList) {
1962 std::vector<double> nominalVoltage;
1963 std::vector<ElectricalUnit> nominalVoltageUnit;
1964 for (
int i = 0; i < (int)child->
GetParentList().size(); i++) {
1967 nominalVoltage.push_back(parent->GetElectricalData().nominalVoltage);
1968 nominalVoltageUnit.push_back(parent->GetElectricalData().nominalVoltageUnit);
1971 child->SetNominalVoltage(nominalVoltage, nominalVoltageUnit);
1975void Workspace::ResetAllVoltages()
1979 UpdateTextElements();
1983bool Workspace::RunPowerFlow(
bool resetVoltages,
bool showBusyInfo)
1985 auto simProp = m_properties->GetSimulationPropertiesData();
1986 double basePower = simProp.basePower;
1993 for (
auto& element : m_elementList) {
1994 if (
auto emtElement =
dynamic_cast<EMTElement*
>(element.get())) {
1995 if (emtElement->IsOnline()) {
1996 emtElement->UpdateData(m_properties,
true);
2000 bool result =
false;
2001 wxString errorMsg =
"";
2006 wxBusyInfo* info =
nullptr;
2008 info =
new wxBusyInfo(
2011 .Icon(wxIcon(Paths::GetDataPath() +
"/images/ribbon/powerFLow32.png", wxBITMAP_TYPE_PNG))
2012 .Title(_(
"<b>Calculating Power Flow</b>"))
2013 .
Text(_(
"Please wait..."))
2014 .Foreground(*wxWHITE)
2015 .Background(*wxBLACK)
2016 .Transparency(4 * wxALPHA_OPAQUE / 5)
2031 if (resetVoltages) pf.ResetVoltages();
2033 switch (simProp.powerFlowMethod) {
2034 case GAUSS_SEIDEL: {
2035 result = pf.RunGaussSeidel(basePower, simProp.powerFlowMaxIterations, simProp.powerFlowTolerance,
2036 simProp.initAngle, simProp.accFator);
2038 case NEWTON_RAPHSON: {
2039 result = pf.RunNewtonRaphson(basePower, simProp.powerFlowMaxIterations, simProp.powerFlowTolerance,
2040 simProp.initAngle, simProp.newtonInertia);
2042 case GAUSS_NEWTON: {
2044 pf.RunGaussNewton(basePower, simProp.powerFlowMaxIterations, simProp.powerFlowTolerance,
2045 simProp.initAngle, simProp.accFator, simProp.gaussTolerance, simProp.newtonInertia);
2049 errorMsg = pf.GetErrorMessage();
2050 numIt = pf.GetIterations();
2052 if (showBusyInfo)
delete info;
2057 wxMessageDialog msgDialog(
this, errorMsg, _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
2058 msgDialog.ShowModal();
2061 m_statusBar->SetStatusText(
2062 wxString::Format(_(
"Power flow converge with %d iterations (%ld ms)"), numIt, sw.Time()));
2065 UpdateTextElements();
2072bool Workspace::UpdateTextElements()
2074 bool isTexturesOK =
true;
2075 double basePower = m_properties->GetSimulationPropertiesData().basePower;
2080 for (
auto& text : m_textList) {
2081 text->SetFontName(m_properties->GetGeneralPropertiesData().labelFont);
2082 text->SetFontSize(m_properties->GetGeneralPropertiesData().labelFontSize);
2083 text->UpdateText(basePower);
2086 return isTexturesOK;
2089void Workspace::CopySelection()
2092 std::vector<Element*> selectedElements;
2095 for (
auto& element : m_elementList) {
2096 if (
auto bus =
dynamic_cast<Bus*
>(element.get())) {
2097 auto data = bus->GetElectricalData();
2098 data.number = busNumber;
2099 bus->SetElectricalData(data);
2102 if (element->
IsSelected()) { selectedElements.push_back(element.get()); }
2104 for (
auto& text : m_textList) {
2105 if (text->
IsSelected()) { selectedElements.push_back(text.get()); }
2108 if (wxTheClipboard->Open()) {
2109 wxTheClipboard->SetData(dataObject);
2110 wxTheClipboard->Close();
2114bool Workspace::Paste()
2116 if (wxTheClipboard->Open()) {
2119 if (wxTheClipboard->IsSupported(dataObject.GetFormat())) {
2120 if (!wxTheClipboard->GetData(dataObject)) {
2121 wxMessageDialog dialog(
this, _(
"It was not possible to paste from clipboard."), _(
"Error"),
2122 wxOK | wxCENTER | wxICON_ERROR, wxDefaultPosition);
2124 wxTheClipboard->Close();
2129 wxTheClipboard->Close();
2132 wxTheClipboard->Close();
2136 std::vector<Element*> pastedElements;
2137 ElementsLists* elementsLists = dataObject.GetElementsLists();
2140 auto parentList = elementsLists->parentList;
2141 std::vector<Bus*> pastedBusList;
2142 for (
auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
2145 pastedElements.push_back(copy);
2146 pastedBusList.push_back(
static_cast<Bus*
>(copy));
2147 m_elementList.emplace_back(
static_cast<PowerElement*
>(copy));
2152 auto elementLists = elementsLists->elementList;
2153 for (
auto it = elementLists.begin(), itEnd = elementLists.end(); it != itEnd; ++it) {
2157 if (
Text* text =
dynamic_cast<Text*
>(copy)) {
2159 bool elementExist =
false;
2160 for (
auto& element : m_elementList) {
2161 if (text->GetElement() == element.get()) {
2162 elementExist =
true;
2167 pastedElements.push_back(copy);
2168 m_textList.emplace_back(text);
2175 if (currentParent) {
2176 int parentID = currentParent->
GetID();
2177 bool parentCopied =
false;
2178 for (
size_t k = 0; k < pastedBusList.size(); k++) {
2179 Bus* newParent = pastedBusList[k];
2180 if (parentID == newParent->
GetID()) {
2181 parentCopied =
true;
2190 pastedElements.push_back(copy);
2191 m_elementList.emplace_back(
static_cast<PowerElement*
>(copy));
2197 for (
auto it = pastedBusList.begin(), itEnd = pastedBusList.end(); it != itEnd; ++it) {
2200 for (
auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
2202 int childID = currentChild->
GetID();
2203 bool childCopied =
false;
2204 for (
int i = 0; i < (int)pastedElements.size(); i++) {
2205 Element* newChild = pastedElements[i];
2206 if (childID == newChild->
GetID()) {
2218 wxPoint2DDouble leftUpCorner, rightDownCorner;
2219 GetElementsCorners(leftUpCorner, rightDownCorner, pastedElements);
2220 wxPoint2DDouble startPosition = (leftUpCorner + rightDownCorner) / 2.0;
2221 for (
auto it = pastedElements.begin(), itEnd = pastedElements.end(); it != itEnd; ++it) {
2224 element->
Move(m_camera->GetMousePosition());
2225 for (
int i = 0; i < (int)element->
GetParentList().size(); i++) {
2227 element->
MoveNode(parent, m_camera->GetMousePosition());
2232 wxMessageDialog dialog(
this, _(
"It was not possible to paste from clipboard."), _(
"Error"),
2233 wxOK | wxCENTER | wxICON_ERROR, wxDefaultPosition);
2239 m_mode = WorkspaceMode::MODE_PASTE;
2240 m_statusBar->SetStatusText(_(
"Click to paste."));
2246void Workspace::SaveCurrentState()
2249 std::vector< std::shared_ptr<PowerElement> > currentStateElementList;
2250 std::vector< std::shared_ptr<Text> > currentStateTextList;
2252 GetStateListsCopy(m_elementList, m_textList, currentStateElementList, currentStateTextList);
2262 m_elementListState.resize(m_currenteState + 1);
2271 m_textListState.resize(m_currenteState + 1);
2274 if (m_currenteState >= m_maxStates) {
2275 m_currenteState = m_maxStates - 1;
2288 m_elementListState.erase(m_elementListState.begin());
2289 m_textListState.erase(m_textListState.begin());
2292 m_elementListState.emplace_back(currentStateElementList);
2293 m_textListState.emplace_back(currentStateTextList);
2297 wxString pointerStr;
2298 pointerStr.Printf(
"[%d S saved s%d] ", m_currenteState, m_elementListState.size());
2300 for (
auto& element : currentStateElementList) {
2301 pointerStr.Printf(
"%p ", element.get());
2305 pointerStr.Printf(
"[%d S curr s%d] ", m_currenteState, m_elementListState.size());
2307 for (
auto& element : m_elementList) {
2308 pointerStr.Printf(
"%p ", element.get());
2316void Workspace::SetNextState()
2319 if (m_currenteState >= 0 &&
2320 static_cast<size_t>(m_currenteState) < m_elementListState.size() &&
2321 static_cast<size_t>(m_currenteState) < m_textListState.size()) {
2324 GetStateListsCopy(m_elementListState[m_currenteState], m_textListState[m_currenteState], m_elementList, m_textList);
2327#ifdef SHOW_DEBUG_PANEL
2329 wxString pointerStr;
2330 pointerStr.Printf(
"[%d N curr s%d] ", m_currenteState, m_elementListState.size());
2332 for (
Element* element : m_elementList) {
2333 pointerStr.Printf(
"%p ", element);
2341 UpdateTextElements();
2349void Workspace::SetPreviousState()
2352 if (m_currenteState >= 0) {
2355 GetStateListsCopy(m_elementListState[m_currenteState], m_textListState[m_currenteState], m_elementList, m_textList);
2358#ifdef SHOW_DEBUG_PANEL
2360 wxString pointerStr;
2361 pointerStr.Printf(
"[%d P curr s%d] ", m_currenteState, m_elementListState.size());
2363 for (
Element* element : m_elementListState[m_currenteState]) {
2364 pointerStr.Printf(
"%p ", element);
2368 pointerStr.Printf(
"[%d P list s%d] ", m_currenteState, m_elementListState.size());
2370 for (
Element* element : m_elementList) {
2371 pointerStr.Printf(
"%p ", element);
2379 UpdateTextElements();
2387void Workspace::UnselectAll()
2389 for (
auto& element : m_elementList) {
2392 for (
auto& text : m_textList) {
2397void Workspace::EnableHeatMap(
const bool& enable)
2406void Workspace::UpdateElementsID()
2409 for (
auto& element : m_elementList) {
2413 for (
auto& text : m_textList) {
2418void Workspace::OnTimer(wxTimerEvent& event)
2421 m_tipWindow->Close();
2422 m_tipWindow =
nullptr;
2424 if (m_mode == WorkspaceMode::MODE_EDIT) {
2425 for (
auto& element : m_elementList) {
2426 if (element->
Contains(m_camera->GetMousePosition())) {
2428 if (!tipText.IsEmpty()) {
2429 m_tipWindow =
new wxTipWindow(
this, tipText, 10000, &m_tipWindow);
2431 m_tipWindow->SetBoundingRect(wxRect(wxGetMousePosition(), wxSize(1, 1)));
2441void Workspace::SetTextList(
const std::vector< std::shared_ptr<Text> >& textList)
2445 m_textList = std::move(textList);
2447 UpdateTextElements();
2450void Workspace::SetName(wxString name)
2454#ifdef SHOW_DEBUG_PANEL
2455 m_debugFrame->SetTitle(_(
"Debug window: ") + m_name);
2460void Workspace::SetElementList(std::vector< std::shared_ptr<PowerElement> > elementList)
2462 m_elementList = std::move(elementList);
2465void Workspace::SetElementList(std::vector<Element*> elementList)
2467 m_elementList.clear();
2468 for (
auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it)
2469 m_elementList.emplace_back(
static_cast<PowerElement*
>(*it));
2472void Workspace::OnIdle(wxIdleEvent& event)
2494 m_justOpened =
false;
2495 double limits[2] = { 1.05, 0.95 };
2496 m_hmPlane =
new HMPlane(m_width, m_height, limits);
2502std::vector<Element*> Workspace::GetAllElements()
const
2504 std::vector<Element*> allElements;
2506 for (
auto& element : m_elementList) allElements.push_back(element.get());
2507 for (
auto& text : m_textList) allElements.push_back(text.get());
2512bool Workspace::RunFault()
2514 auto simProp = m_properties->GetSimulationPropertiesData();
2515 double basePower = simProp.basePower;
2521 Fault fault(GetElementList());
2522 bool result = fault.RunFaultCalculation(basePower);
2524 wxMessageDialog msgDialog(
this, fault.GetErrorMessage(), _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
2525 msgDialog.ShowModal();
2528 UpdateTextElements();
2534std::vector<Element*> Workspace::GetElementList()
const
2536 std::vector<Element*> elementList;
2537 for (
auto& element : m_elementList) elementList.push_back(element.get());
2541bool Workspace::RunSCPower()
2543 Fault fault(GetElementList());
2544 bool result = fault.RunSCPowerCalcutation(100e6);
2546 wxMessageDialog msgDialog(
this, fault.GetErrorMessage(), _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
2547 msgDialog.ShowModal();
2550 UpdateTextElements();
2556bool Workspace::RunStability()
2561 Electromechanical stability(
this, GetElementList(), m_properties->GetSimulationPropertiesData());
2563 bool result = stability.RunStabilityCalculation();
2565#ifdef SHOW_DEBUG_PANEL
2566 m_debugFrame->AppendDebugMessage(stability.GetDebugMessage());
2572 wxMessageDialog msgDialog(
this, stability.GetErrorMessage(), _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
2573 msgDialog.ShowModal();
2575 m_stabilityTimeVector.clear();
2576 m_stabilityTimeVector = stability.GetTimeVector();
2581 wxMessageDialog msgDialog(
2583 wxString::Format(_(
"The program took %ld ms to run this system.\nDo you wish to open the stability graphics?"),
2585 _(
"Question"), wxYES_NO | wxCENTRE | wxICON_QUESTION);
2586 if (msgDialog.ShowModal() == wxID_YES) {
2587 std::vector<ElementPlotData> plotDataList;
2588 for (
auto& element : m_elementList) {
2590 if (element->GetPlotData(plotData)) plotDataList.push_back(plotData);
2592#ifdef SHOW_SIMULATION_PARAMETERS
2594 plotData.SetName(_(
"Simulation parameters"));
2595 plotData.SetCurveType(ElementPlotData::CurveType::CT_TEST);
2596 plotData.AddData(stability.GetIterationVector(), _(
"Iterations number"));
2597 plotDataList.push_back(plotData);
2599 ChartView* cView =
new ChartView(
this, plotDataList, m_stabilityTimeVector, m_properties->GetGeneralPropertiesData().plotLib);
2605void Workspace::OnMiddleDoubleClick(wxMouseEvent& event)
2611bool Workspace::RunStaticStudies()
2613 bool pfStatus, faultStatus, scStatus, harmStatus;
2614 pfStatus = faultStatus = scStatus = harmStatus =
false;
2616 bool runHarmDistortion = m_properties->GetSimulationPropertiesData().harmDistortionAfterPowerFlow;
2618 pfStatus = RunPowerFlow(runHarmDistortion);
2620 if (m_properties->GetSimulationPropertiesData().faultAfterPowerFlow) {
2621 if (pfStatus) faultStatus = RunFault();
2627 if (m_properties->GetSimulationPropertiesData().scPowerAfterPowerFlow) {
2628 if (pfStatus) scStatus = RunSCPower();
2634 if (runHarmDistortion) {
2635 if (pfStatus) harmStatus = RunHarmonicDistortion(
false);
2641 if (pfStatus && faultStatus && scStatus && harmStatus)
return true;
2646bool Workspace::RunHarmonicDistortion(
bool runPowerFlowBefore)
2648 auto simProp = m_properties->GetSimulationPropertiesData();
2649 double basePower = simProp.basePower;
2654 if (runPowerFlowBefore) {
2655 if (!RunPowerFlow(
true))
return false;
2658 bool hasEMTElement =
false;
2659 for (
auto& element : m_elementList) {
2660 if (
auto emtElement =
dynamic_cast<EMTElement*
>(element.get())) {
2661 if (emtElement->IsOnline()) hasEMTElement =
true;
2665 HarmLoadConnection loadConnection = simProp.harmLoadConnection;
2668 bool result = pq.CalculateDistortions(basePower, loadConnection);
2671 if (hasEMTElement && result) {
2675 .Icon(wxIcon(Paths::GetDataPath() +
"/images/ribbon/harmDist32.png", wxBITMAP_TYPE_PNG))
2676 .Title(_(
"<b>Calculating Harmonic Flow</b>"))
2677 .
Text(_(
"Please wait..."))
2678 .Foreground(*wxWHITE)
2679 .Background(*wxBLACK)
2680 .Transparency(4 * wxALPHA_OPAQUE / 5)
2682 std::vector<double> thdList;
2683 for (
auto const& bus : pq.GetBusList())
2684 thdList.emplace_back(bus->GetElectricalData().thd);
2686 while (error > 1e-3) {
2688 if (!RunPowerFlow(
false,
false))
return false;
2691 bool result = pq.CalculateDistortions(basePower, loadConnection);
2696 for (
auto const& bus : pq.GetBusList()) {
2697 double errorBus = std::abs(bus->GetElectricalData().thd - thdList[i]);
2700 else if (errorBus > error)
2702 thdList[i] = bus->GetElectricalData().thd;
2709 wxMessageDialog msgDialog(
this, pq.GetErrorMessage(), _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
2710 msgDialog.ShowModal();
2713 UpdateTextElements();
2720bool Workspace::RunFrequencyResponse()
2723 std::vector<Bus*> busList;
2724 for (
auto& element : m_elementList) {
2725 if (
Bus* bus =
dynamic_cast<Bus*
>(element.get())) { busList.push_back(bus); }
2728 auto data = m_properties->GetFreqRespData();
2730 FrequencyResponseForm frForm(
this, busList, data.injBusNumber, data.initFreq, data.finalFreq, data.stepFreq);
2732 if (frForm.ShowModal() == wxID_OK) {
2733 data.initFreq = frForm.GetInitFreq();
2734 data.finalFreq = frForm.GetEndFreq();
2735 data.stepFreq = frForm.GetStepFreq();
2736 data.injBusNumber = frForm.GetInjBusNumber();
2737 m_properties->SetFreqRespData(data);
2742 auto simProp = m_properties->GetSimulationPropertiesData();
2743 double basePower = simProp.basePower;
2749 bool result = pq.CalculateFrequencyResponse(simProp.stabilityFrequency, data.initFreq, data.finalFreq,
2750 data.stepFreq, data.injBusNumber, basePower, simProp.harmLoadConnection);
2752 wxMessageDialog msgDialog(
2753 this, wxString::Format(_(
"Calculations done.\nDo you wish to open the frequency response graphics?")),
2754 _(
"Question"), wxYES_NO | wxCENTRE | wxICON_QUESTION);
2755 if (msgDialog.ShowModal() == wxID_YES) {
2756 std::vector<ElementPlotData> plotDataList;
2757 for (
auto& element : m_elementList) {
2762 ChartView* cView =
new ChartView(
this, plotDataList, pq.GetFrequencies(), m_properties->GetGeneralPropertiesData().plotLib);
2766 UpdateTextElements();
2771void Workspace::OnResize(wxSizeEvent& event)
2783 m_width =
static_cast<float>(GetSize().x) - 1.0f;
2784 m_height =
static_cast<float>(GetSize().y) - 1.0f;
2786 if (m_hmPlane && m_showHM) {
2787 m_hmPlane->ResizeDC(m_width, m_height);
2788 m_showHMTimer =
true;
2789 m_timerHeatMap->Start();
2794void Workspace::OnHeatMapTime(wxTimerEvent& event)
2796 if (m_showHMTimer) {
2799 m_showHMTimer =
false;
ElectricalUnit
Electrical units.
Node for power elements. All others power elements are connected through this.
Class responsible for the correct visualization of the elements on screen.
This class is responsible to manage the charts generated in the transient electromechanical studies.
Element to connect ATP-EMTP.
Calculates the electromechanical transient based on disturbances (e.g. system fault).
Class to store the elements in the clipboard.
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
virtual Element * GetCopy()
Get a the element copy.
virtual std::vector< Element * > GetParentList() const
Get the parent list.
virtual int GetID() const
Get the element ID.
virtual void UpdateNodes()
Update the nodes according to the parents. If a parent is removed, use this method.
virtual std::vector< wxPoint2DDouble > GetPointList() const
Get the list of points that connect the element to bus.
void SetSelected(bool selected=true)
Set element selection.
wxPoint2DDouble GetPosition() const
Get the element position.
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus,...
virtual void CalculateBoundaries(wxPoint2DDouble &leftUp, wxPoint2DDouble &rightBottom) const
Calculate the element boundaries.
virtual std::vector< Element * > GetChildList() const
Get the Child list.
virtual void RemoveChild(Element *child)
Remove a child from the list.
virtual void ReplaceParent(Element *oldParent, Element *newParent)
Replace a parent.
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
virtual void MoveNode(Element *parent, wxPoint2DDouble position)
Move a node. StartMove(wxPoint2DDouble position) before start moving.
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
virtual void RemoveParent(Element *parent)
Remove a parent.
virtual void SetID(int id)
Set the element ID.
virtual wxString GetTipText() const
Get the tip text.
virtual void Move(wxPoint2DDouble position)
Move the element other position.
virtual bool Contains(wxPoint2DDouble position) const =0
Checks if the element contains a position.
bool IsSelected() const
Checks if the element is selected.
virtual void ReplaceChild(Element *oldChild, Element *newChild)
Replace a child from the list.
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
virtual void RotateNode(Element *parent, bool clockwise=true)
Rotate a node.
virtual void Rotate(bool clockwise=true)
Rotate the element.
Calculate the fault of the system and update the elements data.
Save and opens the projects created on disk.
Abstract class of power elements.
Calculate the power flow.
Responsible for the power quality calculations.
General and simulation data manager.
Element that shows power element informations in workspace.
virtual Element * GetCopy()
Get a the element copy.
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element's rect intersects other rect.
virtual void Rotate(bool clockwise=true)
Rotate the element.