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"
53#include <wx/busyinfo.h>
57Workspace::Workspace() : WorkspaceBase(nullptr)
60#ifdef SHOW_DEBUG_PANEL
62 m_debugFrame->SetTitle(_(
"Debug window: ") + m_name);
67 SetBackgroundColour(wxColour(255, 255, 255));
68 SetBackgroundStyle(wxBG_STYLE_PAINT);
71Workspace::Workspace(wxWindow* parent, wxString name, wxStatusBar* statusBar, wxAuiNotebook* auiNotebook)
72 : WorkspaceBase(parent)
75#ifdef SHOW_DEBUG_PANEL
77 m_debugFrame->SetTitle(_(
"Debug window: ") + m_name);
85 m_statusBar = statusBar;
86 m_auiNotebook = auiNotebook;
89 m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
91 for (
int i = 0; i < NUM_ELEMENTS; ++i) { m_elementNumber[i] = 1; }
93 const int widths[4] = { -3, -1, 100, 100 };
94 m_statusBar->SetStatusWidths(4, widths);
99 m_workspacePanel->SetBackgroundColour(wxColour(255, 255, 255));
100 m_workspacePanel->SetBackgroundStyle(wxBG_STYLE_PAINT);
104 m_width =
static_cast<float>(m_workspacePanel->GetSize().x) - 1.0;
105 m_height =
static_cast<float>(m_workspacePanel->GetSize().y) - 1.0;
111Workspace::~Workspace()
120 if (m_hmPlane)
delete m_hmPlane;
122 if (m_camera)
delete m_camera;
127 if (m_tipWindow)
delete m_tipWindow;
128 if (m_properties)
delete m_properties;
131void Workspace::OnPaint(wxPaintEvent& event)
133 wxBufferedPaintDC dc(m_workspacePanel);
135 wxGraphicsContext* gc = wxGraphicsContext::Create(dc);
144void Workspace::DrawScene(wxGraphicsContext* gc)
150 if (m_hmPlane && m_showHM) {
151 m_hmPlane->DrawDC(gc);
154 gc->Scale(m_camera->GetScale(), m_camera->GetScale());
155 gc->Translate(m_camera->GetTranslation().m_x, m_camera->GetTranslation().m_y);
158 for (
auto& element : m_elementList) {
159 element->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), gc);
164 Text* text =
new Text(wxPoint2DDouble(0.0, 0.0), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
166 text->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), gc);
170 for (
auto& text : m_textList) {
171 text->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), gc);
175 gc->SetPen(wxPen(wxColour(0, 125, 255, 255)));
176 gc->SetBrush(wxBrush(wxColour(0, 125, 255, 125)));
177 gc->DrawRectangle(m_selectionRect.m_x, m_selectionRect.m_y, m_selectionRect.m_width, m_selectionRect.m_height);
179 if (m_hmPlane && m_showHM) {
180 m_hmPlane->DrawLabelDC(gc);
185void Workspace::DrawScene(wxDC& dc)
188 if (m_hmPlane && m_showHM) {
189 m_hmPlane->DrawDC(dc);
192 dc.SetUserScale(m_camera->GetScale(), m_camera->GetScale());
193 dc.SetDeviceOrigin(m_camera->GetTranslation().m_x * m_camera->GetScale(), m_camera->GetTranslation().m_y * m_camera->GetScale());
197 for (
auto& element : m_elementList) {
198 element->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), dc);
203 Text* text =
new Text(wxPoint2DDouble(0.0, 0.0), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
205 text->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), dc);
209 for (
auto& text : m_textList) {
210 text->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), dc);
213 if (m_hmPlane && m_showHM) {
214 m_hmPlane->DrawLabelDC(dc);
218void Workspace::CopyToClipboard()
220 wxSize size = GetClientSize();
224 wxBitmap bitmap(size.x * scale, size.y * scale);
225 wxMemoryDC memDC(bitmap);
227 memDC.SetBackground(*wxWHITE_BRUSH);
230 wxGraphicsContext* gc = wxGraphicsContext::Create(memDC);
232 gc->Scale(scale, scale);
237 memDC.SelectObject(wxNullBitmap);
239 if (wxTheClipboard->Open())
241 wxTheClipboard->SetData(
new wxBitmapDataObject(bitmap));
242 wxTheClipboard->Close();
246void Workspace::ExportAsSVG(wxString path)
248 wxSize size = GetClientSize();
250 wxSVGFileDC svgDC(path, size.x, size.y);
252 svgDC.SetClippingRegion(wxRect(0, 0, size.x, size.y));
257void Workspace::OnLeftClickDown(wxMouseEvent& event)
259 wxPoint clickPoint =
event.GetPosition();
260 bool foundElement =
false;
262 bool showNewElementForm =
false;
263 bool clickOnSwitch =
false;
264 bool unselectAll =
true;
265 std::vector<Element*> notUnselectElementList;
266 std::vector<Text*> notUnselectTextList;
268 if (m_mode == WorkspaceMode::MODE_INSERT_TEXT || m_mode == WorkspaceMode::MODE_PASTE || m_mode == WorkspaceMode::MODE_DRAG_PASTE) {
269 m_mode = WorkspaceMode::MODE_EDIT;
272 else if (m_mode == WorkspaceMode::MODE_INSERT || m_mode == WorkspaceMode::MODE_DRAG_INSERT || m_mode == WorkspaceMode::MODE_DRAG_INSERT_TEXT) {
273 wxPoint2DDouble clickPointWorld = m_camera->ScreenToWorld(clickPoint);
275 if (!m_elementList.empty()) {
277 newElement = m_elementList.back().get();
278 for (
auto& element : m_elementList) {
280 if (element->Contains(clickPointWorld)) {
282 if (
auto bus =
dynamic_cast<Bus*
>(element.get())) {
288 if (newElement->
AddParent(bus, clickPointWorld)) {
289 ValidateElementsVoltages();
291 showNewElementForm =
true;
292 m_mode = WorkspaceMode::MODE_EDIT;
301 if (
auto line =
dynamic_cast<Line*
>(newElement)) { line->AddPoint(clickPointWorld); }
309 bool clickPickbox =
false;
311 for (
auto& element : m_elementList) {
312 element->ResetPickboxes();
315 element->StartMove(m_camera->ScreenToWorld(clickPoint));
318 if (element->NodeContains(m_camera->ScreenToWorld(clickPoint)) != 0 && element->IsSelected()) {
319 m_mode = WorkspaceMode::MODE_MOVE_NODE;
320 m_disconnectedElement =
true;
323 if (m_hmPlane && m_showHM) {
329 else if (element->Contains(m_camera->ScreenToWorld(clickPoint))) {
330 notUnselectElementList.emplace_back(element.get());
332 if (element->IsSelected()) unselectAll =
false;
334 element->SetSelected();
335 element->ShowPickbox();
338 for (
auto& text : m_textList) {
339 if (text->GetElement() == element.get()) {
340 notUnselectTextList.emplace_back(text.get());
342 text->SetAllowRotation(
false);
343 if (unselectAll) text->SetAltSelectionColour();
348 if (element->PickboxContains(m_camera->ScreenToWorld(clickPoint))) {
349 m_mode = WorkspaceMode::MODE_MOVE_PICKBOX;
353 if (!clickPickbox) { m_mode = WorkspaceMode::MODE_MOVE_ELEMENT; }
355 if (m_hmPlane && m_showHM) {
361 else if (element->SwitchesContains(m_camera->ScreenToWorld(clickPoint))) {
362 element->SetOnline(element->IsOnline() ?
false : true);
363 clickOnSwitch =
true;
368 for (
auto& text : m_textList) {
369 text->
StartMove(m_camera->ScreenToWorld(clickPoint));
371 if (text->
Contains(m_camera->ScreenToWorld(clickPoint))) {
372 notUnselectTextList.emplace_back(text.get());
376 text->SetAltSelectionColour(
false);
377 text->SetAllowRotation();
378 m_mode = WorkspaceMode::MODE_MOVE_ELEMENT;
380 if (m_hmPlane && m_showHM) {
389 if (!event.ControlDown() && unselectAll) {
390 for (
auto& element : m_elementList) {
392 for (
Element* notUnselectElement : notUnselectElementList) {
393 if (notUnselectElement == element.get()) select =
true;
395 element->SetSelected(select);
397 for (
auto& text : m_textList) {
399 for (
auto& notUnselectText : notUnselectTextList) {
400 if (notUnselectText == text.get()) select =
true;
406 if (!foundElement && !clickOnSwitch) {
407 m_mode = WorkspaceMode::MODE_SELECTION_RECT;
408 m_startSelRect = m_camera->ScreenToWorld(clickPoint);
409 if (m_hmPlane && m_showHM) {
417 if (showNewElementForm) {
419 newElement->
ShowForm(
this, newElement);
420 CheckSlackBusDuplication(newElement);
422 if (m_continuousCalc) RunStaticStudies();
425 if (clickOnSwitch && m_continuousCalc) RunStaticStudies();
430void Workspace::OnLeftDoubleClick(wxMouseEvent& event)
432 bool elementEdited =
false;
433 bool clickOnSwitch =
false;
436 for (
auto& element : m_elementList) {
438 if (element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
439 bool elementIsBus =
false;
441 Bus* currentBus =
nullptr;
442 if ((currentBus =
dynamic_cast<Bus*
>(element.get()))) {
444 oldBus = *currentBus;
447 if (element->ShowForm(
this, element.get())) {
448 CheckSlackBusDuplication(element.get());
451 elementEdited =
true;
458 if (oldBus.GetElectricalData().nominalVoltage != currentBus->GetElectricalData().nominalVoltage ||
459 oldBus.GetElectricalData().nominalVoltageUnit !=
460 currentBus->GetElectricalData().nominalVoltageUnit) {
462 std::vector<Element*> childList = element->GetChildList();
463 for (
auto itc = childList.begin(), itcEnd = childList.end(); itc != itcEnd; ++itc) {
465 if (
typeid(*child) ==
typeid(
Line)) {
466 wxMessageDialog msgDialog(
this, _(
"Do you want to change the rated voltage of the path?"),
467 _(
"Warning"), wxYES_NO | wxCENTRE | wxICON_WARNING);
468 if (msgDialog.ShowModal() == wxID_YES)
469 ValidateBusesVoltages(element.get());
471 auto data = currentBus->GetElectricalData();
472 data.nominalVoltage = oldBus.GetElectricalData().nominalVoltage;
473 data.nominalVoltageUnit = oldBus.GetElectricalData().nominalVoltageUnit;
474 currentBus->SetElectricalData(data);
480 ValidateElementsVoltages();
485 else if (element->SwitchesContains(m_camera->ScreenToWorld(event.GetPosition()))) {
486 element->SetOnline(element->IsOnline() ?
false : true);
487 clickOnSwitch =
true;
492 for (
auto& text : m_textList) {
493 if (text->
Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
494 if (text->ShowForm(
this, GetElementList())) SaveCurrentState();
499 UpdateTextElements();
500 if (m_continuousCalc) RunStaticStudies();
502 if (clickOnSwitch && m_continuousCalc) RunStaticStudies();
504 if (redraw) Redraw();
508void Workspace::OnRightClickDown(wxMouseEvent& event)
511 if (m_mode == WorkspaceMode::MODE_EDIT) {
512 for (
auto& element : m_elementList) {
513 if (element->IsSelected()) {
515 if (element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
516 element->ShowPickbox(
false);
518 menu.SetClientData(element.get());
519 if (element->GetContextMenu(menu)) {
521 menu.Bind(wxEVT_COMMAND_MENU_SELECTED, &Workspace::OnPopupClick,
this);
525 if (!menu.GetClientData())
break;
527 element->ResetPickboxes();
532 if (redraw) Redraw();
536void Workspace::OnLeftClickUp(wxMouseEvent& event)
540 bool foundPickbox =
false;
541 bool findNewParent =
false;
542 bool updateVoltages =
false;
543 bool saveCurrentState =
false;
544 auto itnp = m_elementList.begin();
546 for (
auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
549 if (m_mode == WorkspaceMode::MODE_MOVE_PICKBOX) {
551 if (element->IsPickboxShown()) {
552 saveCurrentState =
true;
554 if (
auto bus =
dynamic_cast<Bus*
>(element.get())) {
556 for (
auto child : m_elementList) {
557 for (
auto parent : child->GetParentList()) {
561 m_disconnectedElement =
true;
580 if (m_mode == WorkspaceMode::MODE_SELECTION_RECT) {
581 if (element->Intersects(m_selectionRect)) {
582 element->SetSelected();
584 for (
auto& text : m_textList) {
585 if (text->GetElement() == element.get()) {
587 text->SetAltSelectionColour(
false);
588 text->SetAllowRotation();
596 else if (m_mode == WorkspaceMode::MODE_MOVE_NODE) {
597 if (element->IsSelected()) {
598 saveCurrentState =
true;
599 for (
auto parent : m_elementList) {
600 if (
auto bus =
dynamic_cast<Bus*
>(parent.get())) {
601 if (element->SetNodeParent(bus)) {
602 parent->AddChild(element.get());
603 findNewParent =
true;
605 element->ResetNodes();
619 if (element->PickboxContains(m_camera->ScreenToWorld(event.GetPosition()))) {
623 element->ShowPickbox(
false);
624 element->ResetPickboxes();
630 for (
auto& text : m_textList) {
631 if (m_mode == WorkspaceMode::MODE_SELECTION_RECT) {
634 text->SetAltSelectionColour(
false);
635 text->SetAllowRotation();
645 if (m_mode == WorkspaceMode::MODE_MOVE_ELEMENT) saveCurrentState =
true;
648 std::rotate(itnp, itnp + 1, m_elementList.end());
649 updateVoltages =
true;
651 if (!foundPickbox) { SetCursor(wxCURSOR_ARROW); }
653 if (m_mode != WorkspaceMode::MODE_INSERT) { m_mode = WorkspaceMode::MODE_EDIT; }
655 if (updateVoltages) { ValidateElementsVoltages(); }
657 if (saveCurrentState) SaveCurrentState();
659 if (m_continuousCalc && m_disconnectedElement) {
660 m_disconnectedElement =
false;
664 m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
666 if (m_hmPlane && m_showHM) {
667 m_showHMTimer =
true;
668 m_timerHeatMap->Start();
675void Workspace::OnMouseMotion(wxMouseEvent& event)
679 case WorkspaceMode::MODE_INSERT: {
680 auto& newElement = m_elementList.back();
681 newElement->
SetPosition(m_camera->ScreenToWorld(event.GetPosition()));
685 case WorkspaceMode::MODE_INSERT_TEXT: {
686 auto& newText = m_textList.back();
687 newText->SetPosition(m_camera->ScreenToWorld(event.GetPosition()));
691 case WorkspaceMode::MODE_DRAG:
692 case WorkspaceMode::MODE_DRAG_INSERT:
693 case WorkspaceMode::MODE_DRAG_INSERT_TEXT:
694 case WorkspaceMode::MODE_DRAG_PASTE: {
695 m_camera->SetTranslation(event.GetPosition());
699 case WorkspaceMode::MODE_EDIT: {
700 bool foundPickbox =
false;
701 for (
auto& element : m_elementList) {
702 if (element->IsSelected()) {
704 if (element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
705 element->ShowPickbox();
709 if (element->PickboxContains(m_camera->ScreenToWorld(event.GetPosition()))) {
711 SetCursor(element->GetBestPickboxCursor());
713 else if (!foundPickbox) {
714 SetCursor(wxCURSOR_ARROW);
715 element->ResetPickboxes();
718 else if (!foundPickbox) {
719 if (element->IsPickboxShown()) redraw =
true;
721 element->ShowPickbox(
false);
722 element->ResetPickboxes();
723 SetCursor(wxCURSOR_ARROW);
729 case WorkspaceMode::MODE_MOVE_NODE: {
730 for (
auto& element : m_elementList) {
731 if (element->IsSelected()) {
732 element->MoveNode(
nullptr, m_camera->ScreenToWorld(event.GetPosition()));
738 case WorkspaceMode::MODE_MOVE_PICKBOX: {
739 for (
auto& element : m_elementList) {
740 if (element->IsSelected()) {
741 element->MovePickbox(m_camera->ScreenToWorld(event.GetPosition()));
745 if (m_hmPlane && m_showHM) {
750 case WorkspaceMode::MODE_MOVE_ELEMENT:
751 case WorkspaceMode::MODE_PASTE: {
752 for (
auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
754 if (element->IsSelected()) {
755 element->Move(m_camera->ScreenToWorld(event.GetPosition()));
757 std::vector<Element*> childList = element->GetChildList();
758 for (
auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
759 (*it)->MoveNode(element.get(), m_camera->ScreenToWorld(event.GetPosition()));
765 for (
auto& text : m_textList) {
767 text->
Move(m_camera->ScreenToWorld(event.GetPosition()));
771 if (m_hmPlane && m_showHM) {
776 case WorkspaceMode::MODE_SELECTION_RECT: {
777 wxPoint2DDouble currentPos = m_camera->ScreenToWorld(event.GetPosition());
779 if (currentPos.m_x < m_startSelRect.m_x) {
781 w = m_startSelRect.m_x - currentPos.m_x;
784 x = m_startSelRect.m_x;
785 w = currentPos.m_x - m_startSelRect.m_x;
787 if (currentPos.m_y < m_startSelRect.m_y) {
789 h = m_startSelRect.m_y - currentPos.m_y;
792 y = m_startSelRect.m_y;
793 h = currentPos.m_y - m_startSelRect.m_y;
796 m_selectionRect = wxRect2DDouble(x, y, w, h);
804 m_camera->UpdateMousePosition(event.GetPosition());
810void Workspace::OnMiddleDown(wxMouseEvent& event)
814 case WorkspaceMode::MODE_INSERT: {
815 m_mode = WorkspaceMode::MODE_DRAG_INSERT;
817 case WorkspaceMode::MODE_INSERT_TEXT: {
818 m_mode = WorkspaceMode::MODE_DRAG_INSERT_TEXT;
820 case WorkspaceMode::MODE_PASTE: {
821 m_mode = WorkspaceMode::MODE_DRAG_PASTE;
824 m_mode = WorkspaceMode::MODE_DRAG;
827 m_camera->StartTranslation(m_camera->ScreenToWorld(event.GetPosition()));
830 if (m_hmPlane && m_showHM) {
837void Workspace::OnMiddleUp(wxMouseEvent& event)
840 case WorkspaceMode::MODE_DRAG_INSERT: {
841 m_mode = WorkspaceMode::MODE_INSERT;
843 case WorkspaceMode::MODE_DRAG_INSERT_TEXT: {
844 m_mode = WorkspaceMode::MODE_INSERT_TEXT;
846 case WorkspaceMode::MODE_DRAG_PASTE: {
847 m_mode = WorkspaceMode::MODE_PASTE;
849 case WorkspaceMode::MODE_INSERT:
850 case WorkspaceMode::MODE_INSERT_TEXT:
851 case WorkspaceMode::MODE_PASTE: {
855 m_mode = WorkspaceMode::MODE_EDIT;
860 if (m_hmPlane && m_showHM) {
868void Workspace::OnScroll(wxMouseEvent& event)
870 if (event.GetWheelRotation() > 0)
871 m_camera->SetScale(event.GetPosition(), +0.05);
873 m_camera->SetScale(event.GetPosition(), -0.05);
875 if (m_hmPlane && m_showHM) {
877 m_showHMTimer =
true;
878 m_timerHeatMap->Start();
885void Workspace::OnKeyDown(wxKeyEvent& event)
887 bool insertingElement =
false;
888 if (m_mode == WorkspaceMode::MODE_INSERT || m_mode == WorkspaceMode::MODE_INSERT_TEXT) insertingElement =
true;
890 char key =
event.GetUnicodeKey();
891 if (key != WXK_NONE) {
895 if (m_mode == WorkspaceMode::MODE_INSERT) {
897 auto elementToDelete = m_elementList.back();
900 for (
auto& element : m_elementList) {
901 element->RemoveChild(elementToDelete.get());
904 m_elementList.pop_back();
905 m_mode = WorkspaceMode::MODE_EDIT;
908 else if (m_mode == WorkspaceMode::MODE_INSERT_TEXT) {
909 m_textList.pop_back();
910 m_mode = WorkspaceMode::MODE_EDIT;
916 DeleteSelectedElements();
919 if (!insertingElement) {
921 auto newText = std::make_shared<Text>(
922 m_camera->ScreenToWorld(event.GetPosition()),
923 m_properties->GetGeneralPropertiesData().labelFont,
924 m_properties->GetGeneralPropertiesData().labelFontSize);
925 m_textList.push_back(newText);
926 m_mode = WorkspaceMode::MODE_INSERT_TEXT;
927 m_statusBar->SetStatusText(_(
"Insert Text: Click to insert, ESC to cancel."));
928 if (m_hmPlane && m_showHM) {
935 if (event.GetModifiers() == wxMOD_SHIFT) { Fit(); }
939 RotateSelectedElements(event.GetModifiers() != wxMOD_SHIFT);
943 if (!insertingElement) {
944 auto newBus = std::make_shared<Bus>(m_camera->ScreenToWorld(event.GetPosition()),
945 wxString::Format(_(
"Bus %d"), GetElementNumber(ID_BUS)));
946 IncrementElementNumber(ID_BUS);
947 m_elementList.push_back(newBus);
948 m_mode = WorkspaceMode::MODE_INSERT;
949 m_statusBar->SetStatusText(_(
"Insert Bus: Click to insert, ESC to cancel."));
950 if (m_hmPlane && m_showHM) {
957 if (!insertingElement) {
958 if (!event.ControlDown() && event.ShiftDown()) {
959 auto newLoad = std::make_shared<Load>(wxString::Format(_(
"Load %d"), GetElementNumber(ID_LOAD)));
960 IncrementElementNumber(ID_LOAD);
961 m_elementList.push_back(newLoad);
962 m_mode = WorkspaceMode::MODE_INSERT;
963 m_statusBar->SetStatusText(_(
"Insert Load: Click on a bus, ESC to cancel."));
965 else if (!event.ControlDown() && !event.ShiftDown()) {
966 auto newLine = std::make_shared<Line>(wxString::Format(_(
"Line %d"), GetElementNumber(ID_LINE)));
967 IncrementElementNumber(ID_LINE);
968 m_elementList.push_back(newLine);
969 m_mode = WorkspaceMode::MODE_INSERT;
970 m_statusBar->SetStatusText(_(
"Insert Line: Click on two buses, ESC to cancel."));
972 if (m_hmPlane && m_showHM) {
981 if (!insertingElement) {
982 auto newTransformer = std::make_shared<Transformer>(wxString::Format(_(
"Transformer %d"), GetElementNumber(ID_TRANSFORMER)));
983 IncrementElementNumber(ID_TRANSFORMER);
984 m_elementList.push_back(newTransformer);
985 m_mode = WorkspaceMode::MODE_INSERT;
986 m_statusBar->SetStatusText(_(
"Insert Transformer: Click on two buses, ESC to cancel."));
987 if (m_hmPlane && m_showHM) {
995 if (!insertingElement) {
996 auto newGenerator = std::make_shared<SyncGenerator>(wxString::Format(_(
"Generator %d"), GetElementNumber(ID_SYNCGENERATOR)));
997 IncrementElementNumber(ID_SYNCGENERATOR);
998 m_elementList.push_back(newGenerator);
999 m_mode = WorkspaceMode::MODE_INSERT;
1000 m_statusBar->SetStatusText(_(
"Insert Generator: Click on a bus, ESC to cancel."));
1001 if (m_hmPlane && m_showHM) {
1008 if (!insertingElement) {
1009 if (event.GetModifiers() == wxMOD_SHIFT) {
1010 auto newInductor = std::make_shared<Inductor>(wxString::Format(_(
"Inductor %d"), GetElementNumber(ID_INDUCTOR)));
1011 IncrementElementNumber(ID_INDUCTOR);
1012 m_elementList.push_back(newInductor);
1013 m_mode = WorkspaceMode::MODE_INSERT;
1014 m_statusBar->SetStatusText(_(
"Insert Inductor: Click on a bus, ESC to cancel."));
1018 auto newIndMotor = std::make_shared<IndMotor>(wxString::Format(_(
"Induction motor %d"), GetElementNumber(ID_INDMOTOR)));
1019 IncrementElementNumber(ID_INDMOTOR);
1020 m_elementList.push_back(newIndMotor);
1021 m_mode = WorkspaceMode::MODE_INSERT;
1022 m_statusBar->SetStatusText(_(
"Insert Induction Motor: Click on a bus, ESC to cancel."));
1024 if (m_hmPlane && m_showHM) {
1032 if (!insertingElement) {
1033 auto newSyncCondenser = std::make_shared<SyncMotor>(wxString::Format(_(
"Synchronous condenser %d"), GetElementNumber(ID_SYNCMOTOR)));
1034 IncrementElementNumber(ID_SYNCMOTOR);
1035 m_elementList.push_back(newSyncCondenser);
1036 m_mode = WorkspaceMode::MODE_INSERT;
1037 m_statusBar->SetStatusText(_(
"Insert Synchronous Condenser: Click on a bus, ESC to cancel."));
1038 if (m_hmPlane && m_showHM) {
1045 if (!insertingElement) {
1046 if (event.GetModifiers() == wxMOD_SHIFT) {
1047 auto newCapacitor = std::make_shared<Capacitor>(wxString::Format(_(
"Capacitor %d"), GetElementNumber(ID_CAPACITOR)));
1048 IncrementElementNumber(ID_CAPACITOR);
1049 m_elementList.push_back(newCapacitor);
1050 m_mode = WorkspaceMode::MODE_INSERT;
1051 m_statusBar->SetStatusText(_(
"Insert Capacitor: Click on a bus, ESC to cancel."));
1052 if (m_hmPlane && m_showHM) {
1057 else if (event.GetModifiers() == wxMOD_CONTROL) {
1063 if (!insertingElement) {
1064 if (event.ShiftDown() && event.ControlDown()) {
1074 else if (event.GetModifiers() == wxMOD_SHIFT) {
1075 auto newHarmCurrent = std::make_shared<HarmCurrent>(
1076 wxString::Format(_(
"Harmonic Current %d"), GetElementNumber(ID_HARMCURRENT)));
1077 IncrementElementNumber(ID_HARMCURRENT);
1078 m_elementList.push_back(newHarmCurrent);
1079 m_mode = WorkspaceMode::MODE_INSERT;
1080 m_statusBar->SetStatusText(
1081 _(
"Insert Harmonic Current Source: Click on a bus, ESC to cancel."));
1083 if (m_hmPlane && m_showHM) {
1090 if (!insertingElement) {
1091 if (event.GetModifiers() == wxMOD_CONTROL) { Paste(); }
1095 if (!insertingElement) {
1096 if (event.GetModifiers() == wxMOD_CONTROL) {
1100 if (GetSavedPath().IsOk()) {
1101 fileHandling.SaveProject(GetSavedPath());
1104 wxFileDialog saveFileDialog(
this, _(
"Save PSP file"),
"",
"",
"PSP files (*.psp)|*.psp",
1105 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
1106 if (saveFileDialog.ShowModal() == wxID_CANCEL)
return;
1108 fileHandling.SaveProject(saveFileDialog.GetPath());
1109 wxFileName fileName(saveFileDialog.GetPath());
1110 SetName(fileName.GetName());
1111 if (m_auiNotebook) m_auiNotebook->SetPageText(m_auiNotebook->GetPageIndex(
this), GetName());
1112 SetSavedPath(fileName);
1118 if (!insertingElement) {
1119 if (event.ControlDown() && !event.ShiftDown()) { SetPreviousState(); }
1120 if (event.ControlDown() && event.ShiftDown()) { SetNextState(); }
1124 if (!insertingElement) {
1125 if (event.GetModifiers() == wxMOD_CONTROL) { SetNextState(); }
1129 if (!insertingElement) {
1130 if (event.GetModifiers() == wxMOD_SHIFT) {
1132 if (!insertingElement) {
1133 auto newEMTElement = std::make_shared<EMTElement>(wxString::Format(_(
"Electromagnetic Element %d"), GetElementNumber(ID_EMTELEMENT)));
1134 IncrementElementNumber(ID_EMTELEMENT);
1135 m_elementList.push_back(newEMTElement);
1136 m_mode = WorkspaceMode::MODE_INSERT;
1137 m_statusBar->SetStatusText(_(
"Insert Electromagnetic Transient Element: Click on a bus, ESC to cancel."));
1138 if (m_hmPlane && m_showHM) {
1147#ifdef SHOW_DEBUG_PANEL
1149 if (event.GetModifiers() == wxMOD_CONTROL) {
1151 m_debugFrame->SetFocus();
1166void Workspace::UpdateStatusBar()
1169 case WorkspaceMode::MODE_DRAG: {
1170 m_statusBar->SetStatusText(_(
"MODE: DRAG"), 1);
1173 case WorkspaceMode::MODE_PASTE:
1174 case WorkspaceMode::MODE_DRAG_PASTE: {
1175 m_statusBar->SetStatusText(_(
"MODE: PASTE"), 1);
1178 case WorkspaceMode::MODE_INSERT:
1179 case WorkspaceMode::MODE_INSERT_TEXT:
1180 case WorkspaceMode::MODE_DRAG_INSERT:
1181 case WorkspaceMode::MODE_DRAG_INSERT_TEXT: {
1182 m_statusBar->SetStatusText(_(
"MODE: INSERT"), 1);
1185 case WorkspaceMode::MODE_MOVE_ELEMENT:
1186 case WorkspaceMode::MODE_MOVE_PICKBOX:
1187 case WorkspaceMode::MODE_MOVE_NODE:
1188 case WorkspaceMode::MODE_SELECTION_RECT:
1189 case WorkspaceMode::MODE_EDIT: {
1190 if (m_oldStatusMode != m_mode)
1191 m_statusBar->SetStatusText(wxT(
""));
1192 m_statusBar->SetStatusText(_(
"MODE: EDIT"), 1);
1196 m_statusBar->SetStatusText(wxString::Format(_(
"ZOOM: %d%%"), (
int)(m_camera->GetScale() * 100.0)), 2);
1197 m_statusBar->SetStatusText(
1198 wxString::Format(wxT(
"X: %.1f Y: %.1f"), m_camera->GetMousePosition().m_x, m_camera->GetMousePosition().m_y),
1200 m_oldStatusMode = m_mode;
1203int Workspace::GetElementNumberFromList(
Element* element)
1206 for (
auto& elementFromList : m_elementList) {
1207 if (element->GetElementType() == elementFromList->GetElementType()) {
1208 if (element == elementFromList.get())
return elementNum;
1215void Workspace::GetStateListsCopy(
const std::vector< std::shared_ptr<PowerElement> >& elementsList,
1216 const std::vector< std::shared_ptr<Text> >& textList,
1217 std::vector< std::shared_ptr<PowerElement> >& elementsListCopy,
1218 std::vector< std::shared_ptr<Text> >& textListCopy)
1223 elementsListCopy.clear();
1224 textListCopy.clear();
1226 std::map<Element*, Element*> elementMap;
1228 for (
auto& element : elementsList) {
1230 elementsListCopy.emplace_back(copyElement);
1231 elementMap[element.get()] = copyElement;
1234 for (
auto& copyElement : elementsListCopy) {
1237 for (
Element* parent : copyElement->GetParentList()) {
1238 auto it = elementMap.find(parent);
1240 if (it != elementMap.end())
1241 copyElement->SetParent(it->second, i);
1247 for (
Element* child : copyElement->GetChildList()) {
1248 auto it = elementMap.find(child);
1250 if (it != elementMap.end())
1251 copyElement->SetChild(it->second, i);
1257 for (
const auto& text : textList) {
1258 auto copyText =
static_cast<Text*
>(text->
GetCopy());
1260 auto it = elementMap.find(copyText->GetElement());
1262 if (it != elementMap.end())
1263 copyText->SetElement(it->second);
1265 copyText->SetElement(
nullptr);
1266 textListCopy.emplace_back(copyText);
1270void Workspace::UpdateHeatMap()
1272 if (m_hmPlane && m_showHM) {
1275 wxRect2DDouble screenRect(-100, -100, m_width + 200.0, m_height + 200.0);
1278 std::vector<Bus*> busList;
1279 float minVoltage, maxVoltage;
1280 if (m_hmAutomaticLabel) {
1285 minVoltage = m_hmPlane->GetMinLimit();
1286 maxVoltage = m_hmPlane->GetMaxLimit();
1289 for (
auto& element : m_elementList) {
1290 if (
Bus* bus =
dynamic_cast<Bus*
>(element.get())) {
1291 if (m_hmAutomaticLabel) {
1292 const float voltage = std::abs(bus->GetElectricalData().voltage);
1293 if (minVoltage > voltage) minVoltage = voltage;
1294 if (maxVoltage < voltage) maxVoltage = voltage;
1296 busList.push_back(bus);
1299 if (m_hmAutomaticLabel) {
1300 m_hmPlane->SetLabelLimits(minVoltage, maxVoltage);
1303 for (
Bus* bus : busList) {
1304 const float voltage = std::abs(bus->GetElectricalData().voltage);
1305 float depth = 2.0f * (voltage - (maxVoltage + minVoltage) / 2.0f) / (maxVoltage - minVoltage);
1306 if (depth < -1.0) depth = -1.0;
1307 if (depth > 1.0) depth = 1.0;
1309 wxRect2DDouble rect = bus->GetRect();
1310 rect = wxRect2DDouble(
1311 (rect.m_x - 100.0f) * m_camera->GetScale() + m_camera->GetTranslation().m_x * m_camera->GetScale(),
1312 (rect.m_y - 50.0f) * m_camera->GetScale() + m_camera->GetTranslation().m_y * m_camera->GetScale(),
1313 (rect.m_width + 200.0f) * m_camera->GetScale(),
1314 (rect.m_height + 100.0f) * m_camera->GetScale());
1316 if (screenRect.Contains(rect))
1317 m_hmPlane->SetRectSlope(rect, M_PI *
static_cast<float>(bus->GetAngle()) / 180.0f, depth);
1323 int iterations = std::lround(10 * std::pow(m_camera->GetScale(), 2));
1326 if (iterations < 1) iterations = 1;
1327 m_hmPlane->SmoothPlane(iterations);
1331void Workspace::OnPopupClick(wxCommandEvent& event)
1333 bool redrawHM =
false;
1335 wxMenu* menu =
static_cast<wxMenu*
>(
event.GetEventObject());
1337 int eventID =
event.GetId();
1340 if (element->
ShowForm(
this, element)) {
1341 CheckSlackBusDuplication(element);
1342 UpdateTextElements();
1347 Line* line =
static_cast<Line*
>(element);
1348 line->AddNode(m_camera->GetMousePosition());
1353 Line* line =
static_cast<Line*
>(element);
1354 line->RemoveNode(m_camera->GetMousePosition());
1360 for (
auto& iElement : m_elementList) {
1362 for (
int i = 0; i < (int)iElement->GetParentList().size(); i++) {
1364 if (parent == element) { iElement->RotateNode(parent); }
1373 for (
auto& iElement : m_elementList) {
1375 for (
int i = 0; i < (int)iElement->GetParentList().size(); i++) {
1377 if (parent == element) { iElement->RotateNode(parent,
false); }
1424 std::vector<Element*> childList = element->
GetChildList();
1425 for (
auto child : childList) {
1432 std::vector<Element*> parentList = element->
GetParentList();
1433 for (
auto parent : parentList) {
1438 std::erase_if(m_textList, [&](
const auto& text) {
1439 return text->GetElement() == element;
1442 std::erase_if(m_elementList, [&](
const auto& delElement) {
1443 return delElement.get() == element;
1446 menu->SetClientData(
nullptr);
1450 if (InsertTextElement(eventID, element)) {
1451 UpdateTextElements();
1456 if (redrawHM && m_hmPlane && m_showHM) {
1458 m_showHMTimer =
true;
1459 m_timerHeatMap->Start();
1463void Workspace::RotateSelectedElements(
bool clockwise)
1465 bool saveCurrrentState =
false;
1466 for (
auto& element : m_elementList) {
1468 for (
int i = 0; i < (int)element->
GetParentList().size(); i++) {
1475 element->
StartMove(m_camera->GetMousePosition());
1480 saveCurrrentState =
true;
1481 element->
Rotate(clockwise);
1482 element->
StartMove(m_camera->GetMousePosition());
1487 for (
auto& text : m_textList) {
1489 saveCurrrentState =
true;
1491 text->
StartMove(m_camera->GetMousePosition());
1494 if (saveCurrrentState) SaveCurrentState();
1496 if (m_hmPlane && m_showHM) {
1498 m_showHMTimer =
true;
1499 m_timerHeatMap->Start();
1504void Workspace::DeleteSelectedElements()
1507 for (
auto it = m_elementList.begin(); it != m_elementList.end();) {
1512 std::vector<Element*> childList = element->
GetChildList();
1513 for (
auto itc = childList.begin(), itEnd = childList.end(); itc != itEnd; ++itc) {
1520 std::vector<Element*> parentList = element->
GetParentList();
1521 for (
auto itp = parentList.begin(), itEnd = parentList.end(); itp != itEnd; ++itp) {
1536 std::erase_if(m_textList, [&](
const auto& text) {
1537 return text->GetElement() == element;
1540 it = m_elementList.erase(it);
1557 std::erase_if(m_textList, [](
const auto& text) {
1561 if (m_hmPlane && m_showHM) {
1563 m_showHMTimer =
true;
1564 m_timerHeatMap->Start();
1570bool Workspace::GetElementsCorners(wxPoint2DDouble& leftUpCorner,
1571 wxPoint2DDouble& rightDownCorner,
1572 std::vector<Element*> elementList)
1574 if (elementList.size() == 0)
return false;
1576 elementList[0]->CalculateBoundaries(leftUpCorner, rightDownCorner);
1578 for (
auto it = elementList.begin() + 1, itEnd = elementList.end(); it != itEnd; it++) {
1580 wxPoint2DDouble leftUp;
1581 wxPoint2DDouble rightDown;
1583 if (leftUp.m_x < leftUpCorner.m_x) leftUpCorner.m_x = leftUp.m_x;
1584 if (leftUp.m_y < leftUpCorner.m_y) leftUpCorner.m_y = leftUp.m_y;
1585 if (rightDown.m_x > rightDownCorner.m_x) rightDownCorner.m_x = rightDown.m_x;
1586 if (rightDown.m_y > rightDownCorner.m_y) rightDownCorner.m_y = rightDown.m_y;
1591void Workspace::Fit()
1593 wxPoint2DDouble leftUpCorner(0, 0);
1594 wxPoint2DDouble rightDownCorner(0, 0);
1595 std::vector<Element*> elementList = GetElementList();
1596 for (
const auto& text : m_textList) { elementList.push_back(text.get()); }
1598 if (!GetElementsCorners(leftUpCorner, rightDownCorner, elementList))
return;
1599 wxPoint2DDouble middleCoords = (leftUpCorner + rightDownCorner) / 2.0;
1603 GetSize(&width, &height);
1605 double scaleX = double(width) / (rightDownCorner.m_x - leftUpCorner.m_x);
1606 double scaleY = double(height) / (rightDownCorner.m_y - leftUpCorner.m_y);
1608 double scale = scaleX < scaleY ? scaleX : scaleY;
1609 if (scale > m_camera->GetZoomMax()) scale = m_camera->GetZoomMax();
1610 if (scale < m_camera->GetZoomMin()) scale = m_camera->GetZoomMin();
1612 m_camera->SetScale(scale);
1614 m_camera->StartTranslation(middleCoords);
1615 m_camera->SetTranslation(wxPoint2DDouble(width / 2, height / 2));
1617 if (m_hmPlane && m_showHM) {
1624bool Workspace::InsertTextElement(
int textID,
Element* parentElement,
ElectricalUnit unit,
int precision)
1628 if (FindTextElement(parentElement, DATA_NAME))
return false;
1630 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(40, -30), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1631 newText->SetElement(parentElement);
1632 newText->SetDataType(DATA_NAME);
1633 newText->SetElementTypeText(parentElement->GetElementType());
1634 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1636 m_textList.push_back(newText);
1638 case ID_TXT_VOLTAGE: {
1639 if (FindTextElement(parentElement, DATA_VOLTAGE))
return false;
1641 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(40, 15), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1642 newText->SetElement(parentElement);
1643 newText->SetDataType(DATA_VOLTAGE);
1644 if (unit == ElectricalUnit::UNIT_NONE)
1647 newText->SetUnit(unit);
1648 newText->SetDecimalPlaces(precision);
1649 newText->SetElementTypeText(parentElement->GetElementType());
1650 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1652 m_textList.emplace_back(newText);
1654 case ID_TXT_ANGLE: {
1655 if (FindTextElement(parentElement, DATA_ANGLE))
return false;
1657 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(40, 30), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1658 newText->SetElement(parentElement);
1659 newText->SetDataType(DATA_ANGLE);
1660 if (unit == ElectricalUnit::UNIT_NONE)
1663 newText->SetUnit(unit);
1664 newText->SetDecimalPlaces(precision);
1665 newText->SetElementTypeText(parentElement->GetElementType());
1666 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1668 m_textList.emplace_back(newText);
1670 case ID_TXT_FAULTCURRENT: {
1671 if (FindTextElement(parentElement, DATA_SC_CURRENT))
return false;
1673 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(-70, 30), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1674 newText->SetElement(parentElement);
1675 newText->SetDataType(DATA_SC_CURRENT);
1676 if (unit == ElectricalUnit::UNIT_NONE)
1679 newText->SetUnit(unit);
1680 newText->SetDecimalPlaces(precision);
1681 newText->SetElementTypeText(parentElement->GetElementType());
1682 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1684 m_textList.emplace_back(newText);
1686 case ID_TXT_FAULTVOLTAGE: {
1687 if (FindTextElement(parentElement, DATA_SC_VOLTAGE))
return false;
1689 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(-70, 75), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1690 newText->SetElement(parentElement);
1691 newText->SetDataType(DATA_SC_VOLTAGE);
1692 if (unit == ElectricalUnit::UNIT_NONE)
1695 newText->SetUnit(unit);
1696 newText->SetDecimalPlaces(precision);
1697 newText->SetElementTypeText(parentElement->GetElementType());
1698 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1700 m_textList.emplace_back(newText);
1703 if (FindTextElement(parentElement, DATA_SC_POWER))
return false;
1704 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(-50, -30), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1705 newText->SetElement(parentElement);
1706 newText->SetDataType(DATA_SC_POWER);
1708 if (unit == ElectricalUnit::UNIT_NONE)
1711 newText->SetUnit(unit);
1712 newText->SetDecimalPlaces(precision);
1713 newText->SetElementTypeText(parentElement->GetElementType());
1714 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1716 m_textList.emplace_back(newText);
1719 if (FindTextElement(parentElement, DATA_PQ_THD))
return false;
1720 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(-50, -15), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1721 newText->SetElement(parentElement);
1722 newText->SetDataType(DATA_PQ_THD);
1723 newText->SetDecimalPlaces(precision);
1724 newText->SetElementTypeText(parentElement->GetElementType());
1725 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1727 m_textList.emplace_back(newText);
1729 case ID_TXT_ACTIVE_POWER: {
1730 if (FindTextElement(parentElement, DATA_ACTIVE_POWER))
return false;
1731 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(0, 35), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1732 newText->SetElement(parentElement);
1733 newText->SetDataType(DATA_ACTIVE_POWER);
1734 if (unit == ElectricalUnit::UNIT_NONE)
1737 newText->SetUnit(unit);
1738 newText->SetDecimalPlaces(precision);
1739 newText->SetElementTypeText(parentElement->GetElementType());
1740 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1742 m_textList.emplace_back(newText);
1744 case ID_TXT_REACTIVE_POWER: {
1745 if (FindTextElement(parentElement, DATA_REACTIVE_POWER))
return false;
1746 auto newText = std::make_shared<Text>(parentElement->
GetPosition() + wxPoint2DDouble(0, 50), m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1747 newText->SetElement(parentElement);
1748 newText->SetDataType(DATA_REACTIVE_POWER);
1749 if (unit == ElectricalUnit::UNIT_NONE)
1752 newText->SetUnit(unit);
1753 newText->SetDecimalPlaces(precision);
1754 newText->SetElementTypeText(parentElement->GetElementType());
1755 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1757 m_textList.emplace_back(newText);
1759 case ID_TXT_BRANCH_ACTIVE_POWER_1_2:
1760 case ID_TXT_BRANCH_ACTIVE_POWER_2_1: {
1761 if (FindTextElement(parentElement, DATA_PF_ACTIVE))
return false;
1762 wxPoint2DDouble position(0.0, -10.0);
1763 if (textID == ID_TXT_BRANCH_ACTIVE_POWER_1_2)
1768 auto newText = std::make_shared<Text>(position, m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1769 newText->SetElement(parentElement);
1770 newText->SetDataType(DATA_PF_ACTIVE);
1771 if (unit == ElectricalUnit::UNIT_NONE)
1774 newText->SetUnit(unit);
1775 newText->SetDecimalPlaces(precision);
1776 newText->SetElementTypeText(parentElement->GetElementType());
1777 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1778 if (textID == ID_TXT_BRANCH_ACTIVE_POWER_2_1)
1779 newText->SetDirection(1);
1781 m_textList.emplace_back(newText);
1783 case ID_TXT_BRANCH_REACTIVE_POWER_1_2:
1784 case ID_TXT_BRANCH_REACTIVE_POWER_2_1: {
1785 if (FindTextElement(parentElement, DATA_PF_REACTIVE))
return false;
1786 wxPoint2DDouble position(0.0, 10.0);
1787 if (textID == ID_TXT_BRANCH_REACTIVE_POWER_1_2)
1792 auto newText = std::make_shared<Text>(position, m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1793 newText->SetElement(parentElement);
1794 newText->SetDataType(DATA_PF_REACTIVE);
1795 if (unit == ElectricalUnit::UNIT_NONE)
1798 newText->SetUnit(unit);
1799 newText->SetDecimalPlaces(precision);
1800 newText->SetElementTypeText(parentElement->GetElementType());
1801 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1802 if (textID == ID_TXT_BRANCH_REACTIVE_POWER_2_1)
1803 newText->SetDirection(1);
1805 m_textList.emplace_back(newText);
1807 case ID_TXT_BRANCH_LOSSES: {
1808 if (FindTextElement(parentElement, DATA_PF_LOSSES))
return false;
1810 auto newText = std::make_shared<Text>(position, m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1811 newText->SetElement(parentElement);
1812 newText->SetDataType(DATA_PF_LOSSES);
1813 if (unit == ElectricalUnit::UNIT_NONE)
1816 newText->SetUnit(unit);
1817 newText->SetDecimalPlaces(precision);
1818 newText->SetElementTypeText(parentElement->GetElementType());
1819 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1821 m_textList.emplace_back(newText);
1823 case ID_TXT_BRANCH_CURRENT_1_2:
1824 case ID_TXT_BRANCH_CURRENT_2_1: {
1825 if (FindTextElement(parentElement, DATA_PF_CURRENT))
return false;
1826 wxPoint2DDouble position(0.0, 10.0);
1827 if (textID == ID_TXT_BRANCH_CURRENT_1_2)
1832 auto newText = std::make_shared<Text>(position, m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1833 newText->SetElement(parentElement);
1834 newText->SetDataType(DATA_PF_CURRENT);
1835 if (unit == ElectricalUnit::UNIT_NONE)
1838 newText->SetUnit(unit);
1839 newText->SetDecimalPlaces(precision);
1840 newText->SetElementTypeText(parentElement->GetElementType());
1841 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1842 if (textID == ID_TXT_BRANCH_CURRENT_2_1)
1843 newText->SetDirection(1);
1845 m_textList.emplace_back(newText);
1847 case ID_TXT_BRANCH_FAULT_CURRENT_1_2:
1848 case ID_TXT_BRANCH_FAULT_CURRENT_2_1: {
1849 if (FindTextElement(parentElement, DATA_SC_CURRENT))
return false;
1850 wxPoint2DDouble position(0.0, 25.0);
1851 if (textID == ID_TXT_BRANCH_FAULT_CURRENT_1_2)
1856 auto newText = std::make_shared<Text>(position, m_properties->GetGeneralPropertiesData().labelFont, m_properties->GetGeneralPropertiesData().labelFontSize);
1857 newText->SetElement(parentElement);
1858 newText->SetDataType(DATA_SC_CURRENT);
1859 if (unit == ElectricalUnit::UNIT_NONE)
1862 newText->SetUnit(unit);
1863 newText->SetDecimalPlaces(precision);
1864 newText->SetElementTypeText(parentElement->GetElementType());
1865 newText->SetElementNumber(GetElementNumberFromList(parentElement));
1866 if (textID == ID_TXT_BRANCH_FAULT_CURRENT_2_1)
1867 newText->SetDirection(1);
1869 m_textList.emplace_back(newText);
1878Element* Workspace::FindTextElement(
Element* parentElement,
int dataType)
1880 for (
auto& text : m_textList) {
1881 if (text->GetElement() == parentElement && text->GetDataType() == dataType)
1887void Workspace::RemoveAllTextElements()
1896void Workspace::CheckSlackBusDuplication(
Element* newSlackBus)
1898 Bus* newBus =
dynamic_cast<Bus*
>(newSlackBus);
1900 if (!newBus->GetElectricalData().slackBus)
return;
1902 for (
auto& element : m_elementList) {
1903 Bus* bus =
dynamic_cast<Bus*
>(element.get());
1905 if (bus->GetElectricalData().slackBus && bus != newSlackBus) {
1906 wxMessageDialog msgDialog(
this,
1907 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),
1908 _(
"Warning"), wxYES_NO | wxCENTRE | wxICON_WARNING);
1909 if (msgDialog.ShowModal() == wxID_YES) {
1910 auto data = bus->GetElectricalData();
1911 data.slackBus =
false;
1912 bus->SetElectricalData(data);
1916 auto data = newBus->GetElectricalData();
1917 data.slackBus =
false;
1918 newBus->SetElectricalData(data);
1926void Workspace::ValidateBusesVoltages(
Element* initialBus)
1928 double nominalVoltage =
static_cast<Bus*
>(initialBus)->GetElectricalData().nominalVoltage;
1929 ElectricalUnit nominalVoltageUnit =
static_cast<Bus*
>(initialBus)->GetElectricalData().nominalVoltageUnit;
1931 for (
auto it = m_elementList.begin(); it != m_elementList.end(); it++) {
1934 if (
auto line =
dynamic_cast<Line*
>(child)) {
1939 if (data1.nominalVoltage != data2.nominalVoltage ||
1940 data1.nominalVoltageUnit != data2.nominalVoltageUnit) {
1941 data1.nominalVoltage = nominalVoltage;
1942 data2.nominalVoltage = nominalVoltage;
1943 data1.nominalVoltageUnit = nominalVoltageUnit;
1944 data2.nominalVoltageUnit = nominalVoltageUnit;
1949 it = m_elementList.begin();
1958void Workspace::ValidateElementsVoltages()
1960 for (
auto& child : m_elementList) {
1961 std::vector<double> nominalVoltage;
1962 std::vector<ElectricalUnit> nominalVoltageUnit;
1963 for (
int i = 0; i < (int)child->
GetParentList().size(); i++) {
1966 nominalVoltage.push_back(parent->GetElectricalData().nominalVoltage);
1967 nominalVoltageUnit.push_back(parent->GetElectricalData().nominalVoltageUnit);
1970 child->SetNominalVoltage(nominalVoltage, nominalVoltageUnit);
1974void Workspace::ResetAllVoltages()
1978 UpdateTextElements();
1982bool Workspace::RunPowerFlow(
bool resetVoltages,
bool showBusyInfo)
1984 auto simProp = m_properties->GetSimulationPropertiesData();
1985 double basePower = simProp.basePower;
1992 for (
auto& element : m_elementList) {
1993 if (
auto emtElement =
dynamic_cast<EMTElement*
>(element.get())) {
1994 if (emtElement->IsOnline()) {
1995 emtElement->UpdateData(m_properties,
true);
1999 bool result =
false;
2000 wxString errorMsg =
"";
2005 wxBusyInfo* info =
nullptr;
2007 info =
new wxBusyInfo(
2010 .Icon(wxIcon(wxT(
"..\\data\\images\\ribbon\\powerFLow32.png"), wxBITMAP_TYPE_PNG))
2011 .Title(_(
"<b>Calculating Power Flow</b>"))
2012 .
Text(_(
"Please wait..."))
2013 .Foreground(*wxWHITE)
2014 .Background(*wxBLACK)
2015 .Transparency(4 * wxALPHA_OPAQUE / 5)
2030 if (resetVoltages) pf.ResetVoltages();
2032 switch (simProp.powerFlowMethod) {
2033 case GAUSS_SEIDEL: {
2034 result = pf.RunGaussSeidel(basePower, simProp.powerFlowMaxIterations, simProp.powerFlowTolerance,
2035 simProp.initAngle, simProp.accFator);
2037 case NEWTON_RAPHSON: {
2038 result = pf.RunNewtonRaphson(basePower, simProp.powerFlowMaxIterations, simProp.powerFlowTolerance,
2039 simProp.initAngle, simProp.newtonInertia);
2041 case GAUSS_NEWTON: {
2043 pf.RunGaussNewton(basePower, simProp.powerFlowMaxIterations, simProp.powerFlowTolerance,
2044 simProp.initAngle, simProp.accFator, simProp.gaussTolerance, simProp.newtonInertia);
2048 errorMsg = pf.GetErrorMessage();
2049 numIt = pf.GetIterations();
2051 if (showBusyInfo)
delete info;
2056 wxMessageDialog msgDialog(
this, errorMsg, _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
2057 msgDialog.ShowModal();
2060 m_statusBar->SetStatusText(
2061 wxString::Format(_(
"Power flow converge with %d iterations (%ld ms)"), numIt, sw.Time()));
2064 UpdateTextElements();
2071bool Workspace::UpdateTextElements()
2073 bool isTexturesOK =
true;
2074 double basePower = m_properties->GetSimulationPropertiesData().basePower;
2079 for (
auto& text : m_textList) {
2080 text->SetFontName(m_properties->GetGeneralPropertiesData().labelFont);
2081 text->SetFontSize(m_properties->GetGeneralPropertiesData().labelFontSize);
2082 text->UpdateText(basePower);
2085 return isTexturesOK;
2088void Workspace::CopySelection()
2091 std::vector<Element*> selectedElements;
2094 for (
auto& element : m_elementList) {
2095 if (
auto bus =
dynamic_cast<Bus*
>(element.get())) {
2096 auto data = bus->GetElectricalData();
2097 data.number = busNumber;
2098 bus->SetElectricalData(data);
2101 if (element->
IsSelected()) { selectedElements.push_back(element.get()); }
2103 for (
auto& text : m_textList) {
2104 if (text->
IsSelected()) { selectedElements.push_back(text.get()); }
2107 if (wxTheClipboard->Open()) {
2108 wxTheClipboard->SetData(dataObject);
2109 wxTheClipboard->Close();
2113bool Workspace::Paste()
2115 if (wxTheClipboard->Open()) {
2118 if (wxTheClipboard->IsSupported(dataObject.GetFormat())) {
2119 if (!wxTheClipboard->GetData(dataObject)) {
2120 wxMessageDialog dialog(
this, _(
"It was not possible to paste from clipboard."), _(
"Error"),
2121 wxOK | wxCENTER | wxICON_ERROR, wxDefaultPosition);
2123 wxTheClipboard->Close();
2128 wxTheClipboard->Close();
2131 wxTheClipboard->Close();
2135 std::vector<Element*> pastedElements;
2136 ElementsLists* elementsLists = dataObject.GetElementsLists();
2139 auto parentList = elementsLists->parentList;
2140 std::vector<Bus*> pastedBusList;
2141 for (
auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
2144 pastedElements.push_back(copy);
2145 pastedBusList.push_back(
static_cast<Bus*
>(copy));
2146 m_elementList.emplace_back(
static_cast<PowerElement*
>(copy));
2151 auto elementLists = elementsLists->elementList;
2152 for (
auto it = elementLists.begin(), itEnd = elementLists.end(); it != itEnd; ++it) {
2156 if (
Text* text =
dynamic_cast<Text*
>(copy)) {
2158 bool elementExist =
false;
2159 for (
auto& element : m_elementList) {
2160 if (text->GetElement() == element.get()) {
2161 elementExist =
true;
2166 pastedElements.push_back(copy);
2167 m_textList.emplace_back(text);
2174 if (currentParent) {
2175 int parentID = currentParent->
GetID();
2176 bool parentCopied =
false;
2177 for (
size_t k = 0; k < pastedBusList.size(); k++) {
2178 Bus* newParent = pastedBusList[k];
2179 if (parentID == newParent->
GetID()) {
2180 parentCopied =
true;
2189 pastedElements.push_back(copy);
2190 m_elementList.emplace_back(
static_cast<PowerElement*
>(copy));
2196 for (
auto it = pastedBusList.begin(), itEnd = pastedBusList.end(); it != itEnd; ++it) {
2199 for (
auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
2201 int childID = currentChild->
GetID();
2202 bool childCopied =
false;
2203 for (
int i = 0; i < (int)pastedElements.size(); i++) {
2204 Element* newChild = pastedElements[i];
2205 if (childID == newChild->
GetID()) {
2217 wxPoint2DDouble leftUpCorner, rightDownCorner;
2218 GetElementsCorners(leftUpCorner, rightDownCorner, pastedElements);
2219 wxPoint2DDouble startPosition = (leftUpCorner + rightDownCorner) / 2.0;
2220 for (
auto it = pastedElements.begin(), itEnd = pastedElements.end(); it != itEnd; ++it) {
2223 element->
Move(m_camera->GetMousePosition());
2224 for (
int i = 0; i < (int)element->
GetParentList().size(); i++) {
2226 element->
MoveNode(parent, m_camera->GetMousePosition());
2231 wxMessageDialog dialog(
this, _(
"It was not possible to paste from clipboard."), _(
"Error"),
2232 wxOK | wxCENTER | wxICON_ERROR, wxDefaultPosition);
2238 m_mode = WorkspaceMode::MODE_PASTE;
2239 m_statusBar->SetStatusText(_(
"Click to paste."));
2245void Workspace::SaveCurrentState()
2248 std::vector< std::shared_ptr<PowerElement> > currentStateElementList;
2249 std::vector< std::shared_ptr<Text> > currentStateTextList;
2251 GetStateListsCopy(m_elementList, m_textList, currentStateElementList, currentStateTextList);
2261 m_elementListState.resize(m_currenteState + 1);
2270 m_textListState.resize(m_currenteState + 1);
2273 if (m_currenteState >= m_maxStates) {
2274 m_currenteState = m_maxStates - 1;
2287 m_elementListState.erase(m_elementListState.begin());
2288 m_textListState.erase(m_textListState.begin());
2291 m_elementListState.emplace_back(currentStateElementList);
2292 m_textListState.emplace_back(currentStateTextList);
2296 wxString pointerStr;
2297 pointerStr.Printf(
"[%d S saved s%d] ", m_currenteState, m_elementListState.size());
2299 for (
auto& element : currentStateElementList) {
2300 pointerStr.Printf(
"%p ", element.get());
2304 pointerStr.Printf(
"[%d S curr s%d] ", m_currenteState, m_elementListState.size());
2306 for (
auto& element : m_elementList) {
2307 pointerStr.Printf(
"%p ", element.get());
2315void Workspace::SetNextState()
2318 if (m_currenteState >= 0 &&
2319 static_cast<size_t>(m_currenteState) < m_elementListState.size() &&
2320 static_cast<size_t>(m_currenteState) < m_textListState.size()) {
2323 GetStateListsCopy(m_elementListState[m_currenteState], m_textListState[m_currenteState], m_elementList, m_textList);
2326#ifdef SHOW_DEBUG_PANEL
2328 wxString pointerStr;
2329 pointerStr.Printf(
"[%d N curr s%d] ", m_currenteState, m_elementListState.size());
2331 for (
Element* element : m_elementList) {
2332 pointerStr.Printf(
"%p ", element);
2340 UpdateTextElements();
2348void Workspace::SetPreviousState()
2351 if (m_currenteState >= 0) {
2354 GetStateListsCopy(m_elementListState[m_currenteState], m_textListState[m_currenteState], m_elementList, m_textList);
2357#ifdef SHOW_DEBUG_PANEL
2359 wxString pointerStr;
2360 pointerStr.Printf(
"[%d P curr s%d] ", m_currenteState, m_elementListState.size());
2362 for (
Element* element : m_elementListState[m_currenteState]) {
2363 pointerStr.Printf(
"%p ", element);
2367 pointerStr.Printf(
"[%d P list s%d] ", m_currenteState, m_elementListState.size());
2369 for (
Element* element : m_elementList) {
2370 pointerStr.Printf(
"%p ", element);
2378 UpdateTextElements();
2386void Workspace::UnselectAll()
2388 for (
auto& element : m_elementList) {
2391 for (
auto& text : m_textList) {
2396void Workspace::EnableHeatMap(
const bool& enable)
2405void Workspace::UpdateElementsID()
2408 for (
auto& element : m_elementList) {
2412 for (
auto& text : m_textList) {
2417void Workspace::OnTimer(wxTimerEvent& event)
2420 m_tipWindow->Close();
2421 m_tipWindow =
nullptr;
2423 if (m_mode == WorkspaceMode::MODE_EDIT) {
2424 for (
auto& element : m_elementList) {
2425 if (element->
Contains(m_camera->GetMousePosition())) {
2427 if (!tipText.IsEmpty()) {
2428 m_tipWindow =
new wxTipWindow(
this, tipText, 10000, &m_tipWindow);
2430 m_tipWindow->SetBoundingRect(wxRect(wxGetMousePosition(), wxSize(1, 1)));
2440void Workspace::SetTextList(
const std::vector< std::shared_ptr<Text> >& textList)
2444 m_textList = std::move(textList);
2446 UpdateTextElements();
2449void Workspace::SetName(wxString name)
2453#ifdef SHOW_DEBUG_PANEL
2454 m_debugFrame->SetTitle(_(
"Debug window: ") + m_name);
2459void Workspace::SetElementList(std::vector< std::shared_ptr<PowerElement> > elementList)
2461 m_elementList = std::move(elementList);
2464void Workspace::SetElementList(std::vector<Element*> elementList)
2466 m_elementList.clear();
2467 for (
auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it)
2468 m_elementList.emplace_back(
static_cast<PowerElement*
>(*it));
2471void Workspace::OnIdle(wxIdleEvent& event)
2493 m_justOpened =
false;
2494 double limits[2] = { 1.05, 0.95 };
2495 m_hmPlane =
new HMPlane(m_width, m_height, limits);
2501std::vector<Element*> Workspace::GetAllElements()
const
2503 std::vector<Element*> allElements;
2505 for (
auto& element : m_elementList) allElements.push_back(element.get());
2506 for (
auto& text : m_textList) allElements.push_back(text.get());
2511bool Workspace::RunFault()
2513 auto simProp = m_properties->GetSimulationPropertiesData();
2514 double basePower = simProp.basePower;
2520 Fault fault(GetElementList());
2521 bool result = fault.RunFaultCalculation(basePower);
2523 wxMessageDialog msgDialog(
this, fault.GetErrorMessage(), _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
2524 msgDialog.ShowModal();
2527 UpdateTextElements();
2533std::vector<Element*> Workspace::GetElementList()
const
2535 std::vector<Element*> elementList;
2536 for (
auto& element : m_elementList) elementList.push_back(element.get());
2540bool Workspace::RunSCPower()
2542 Fault fault(GetElementList());
2543 bool result = fault.RunSCPowerCalcutation(100e6);
2545 wxMessageDialog msgDialog(
this, fault.GetErrorMessage(), _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
2546 msgDialog.ShowModal();
2549 UpdateTextElements();
2555bool Workspace::RunStability()
2560 Electromechanical stability(
this, GetElementList(), m_properties->GetSimulationPropertiesData());
2562 bool result = stability.RunStabilityCalculation();
2564#ifdef SHOW_DEBUG_PANEL
2565 m_debugFrame->AppendDebugMessage(stability.GetDebugMessage());
2571 wxMessageDialog msgDialog(
this, stability.GetErrorMessage(), _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
2572 msgDialog.ShowModal();
2574 m_stabilityTimeVector.clear();
2575 m_stabilityTimeVector = stability.GetTimeVector();
2580 wxMessageDialog msgDialog(
2582 wxString::Format(_(
"The program took %ld ms to run this system.\nDo you wish to open the stability graphics?"),
2584 _(
"Question"), wxYES_NO | wxCENTRE | wxICON_QUESTION);
2585 if (msgDialog.ShowModal() == wxID_YES) {
2586 std::vector<ElementPlotData> plotDataList;
2587 for (
auto& element : m_elementList) {
2589 if (element->GetPlotData(plotData)) plotDataList.push_back(plotData);
2591#ifdef SHOW_SIMULATION_PARAMETERS
2593 plotData.SetName(_(
"Simulation parameters"));
2594 plotData.SetCurveType(ElementPlotData::CurveType::CT_TEST);
2595 plotData.AddData(stability.GetIterationVector(), _(
"Iterations number"));
2596 plotDataList.push_back(plotData);
2598 ChartView* cView =
new ChartView(
this, plotDataList, m_stabilityTimeVector, m_properties->GetGeneralPropertiesData().plotLib);
2604void Workspace::OnMiddleDoubleClick(wxMouseEvent& event)
2610bool Workspace::RunStaticStudies()
2612 bool pfStatus, faultStatus, scStatus, harmStatus;
2613 pfStatus = faultStatus = scStatus = harmStatus =
false;
2615 bool runHarmDistortion = m_properties->GetSimulationPropertiesData().harmDistortionAfterPowerFlow;
2617 pfStatus = RunPowerFlow(runHarmDistortion);
2619 if (m_properties->GetSimulationPropertiesData().faultAfterPowerFlow) {
2620 if (pfStatus) faultStatus = RunFault();
2626 if (m_properties->GetSimulationPropertiesData().scPowerAfterPowerFlow) {
2627 if (pfStatus) scStatus = RunSCPower();
2633 if (runHarmDistortion) {
2634 if (pfStatus) harmStatus = RunHarmonicDistortion(
false);
2640 if (pfStatus && faultStatus && scStatus && harmStatus)
return true;
2645bool Workspace::RunHarmonicDistortion(
bool runPowerFlowBefore)
2647 auto simProp = m_properties->GetSimulationPropertiesData();
2648 double basePower = simProp.basePower;
2653 if (runPowerFlowBefore) {
2654 if (!RunPowerFlow(
true))
return false;
2657 bool hasEMTElement =
false;
2658 for (
auto& element : m_elementList) {
2659 if (
auto emtElement =
dynamic_cast<EMTElement*
>(element.get())) {
2660 if (emtElement->IsOnline()) hasEMTElement =
true;
2664 HarmLoadConnection loadConnection = simProp.harmLoadConnection;
2667 bool result = pq.CalculateDistortions(basePower, loadConnection);
2670 if (hasEMTElement && result) {
2674 .Icon(wxIcon(wxT(
"..\\data\\images\\ribbon\\harmDist32.png"), wxBITMAP_TYPE_PNG))
2675 .Title(_(
"<b>Calculating Harmonic Flow</b>"))
2676 .
Text(_(
"Please wait..."))
2677 .Foreground(*wxWHITE)
2678 .Background(*wxBLACK)
2679 .Transparency(4 * wxALPHA_OPAQUE / 5)
2681 std::vector<double> thdList;
2682 for (
auto const& bus : pq.GetBusList())
2683 thdList.emplace_back(bus->GetElectricalData().thd);
2685 while (error > 1e-3) {
2687 if (!RunPowerFlow(
false,
false))
return false;
2690 bool result = pq.CalculateDistortions(basePower, loadConnection);
2695 for (
auto const& bus : pq.GetBusList()) {
2696 double errorBus = std::abs(bus->GetElectricalData().thd - thdList[i]);
2699 else if (errorBus > error)
2701 thdList[i] = bus->GetElectricalData().thd;
2708 wxMessageDialog msgDialog(
this, pq.GetErrorMessage(), _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
2709 msgDialog.ShowModal();
2712 UpdateTextElements();
2719bool Workspace::RunFrequencyResponse()
2722 std::vector<Bus*> busList;
2723 for (
auto& element : m_elementList) {
2724 if (
Bus* bus =
dynamic_cast<Bus*
>(element.get())) { busList.push_back(bus); }
2727 auto data = m_properties->GetFreqRespData();
2729 FrequencyResponseForm frForm(
this, busList, data.injBusNumber, data.initFreq, data.finalFreq, data.stepFreq);
2731 if (frForm.ShowModal() == wxID_OK) {
2732 data.initFreq = frForm.GetInitFreq();
2733 data.finalFreq = frForm.GetEndFreq();
2734 data.stepFreq = frForm.GetStepFreq();
2735 data.injBusNumber = frForm.GetInjBusNumber();
2736 m_properties->SetFreqRespData(data);
2741 auto simProp = m_properties->GetSimulationPropertiesData();
2742 double basePower = simProp.basePower;
2748 bool result = pq.CalculateFrequencyResponse(simProp.stabilityFrequency, data.initFreq, data.finalFreq,
2749 data.stepFreq, data.injBusNumber, basePower, simProp.harmLoadConnection);
2751 wxMessageDialog msgDialog(
2752 this, wxString::Format(_(
"Calculations done.\nDo you wish to open the frequency response graphics?")),
2753 _(
"Question"), wxYES_NO | wxCENTRE | wxICON_QUESTION);
2754 if (msgDialog.ShowModal() == wxID_YES) {
2755 std::vector<ElementPlotData> plotDataList;
2756 for (
auto& element : m_elementList) {
2761 ChartView* cView =
new ChartView(
this, plotDataList, pq.GetFrequencies(), m_properties->GetGeneralPropertiesData().plotLib);
2765 UpdateTextElements();
2770void Workspace::OnResize(wxSizeEvent& event)
2782 m_width =
static_cast<float>(GetSize().x) - 1.0f;
2783 m_height =
static_cast<float>(GetSize().y) - 1.0f;
2785 if (m_hmPlane && m_showHM) {
2786 m_hmPlane->ResizeDC(m_width, m_height);
2787 m_showHMTimer =
true;
2788 m_timerHeatMap->Start();
2793void Workspace::OnHeatMapTime(wxTimerEvent& event)
2795 if (m_showHMTimer) {
2798 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.