19#include "../../forms/TransformerForm.h"
21Transformer::Transformer() :
Branch()
23 m_elementType = TYPE_TRANSFORMER;
24 for (
int i = 0; i < 2; i++) {
25 for (
int j = 0; j < 3; j++) { m_electricalData.faultCurrent[i][j] = std::complex<double>(0.0, 0.0); }
28Transformer::Transformer(wxString name) :
Branch()
30 m_elementType = TYPE_TRANSFORMER;
31 for (
int i = 0; i < 2; i++) {
32 for (
int j = 0; j < 3; j++) { m_electricalData.faultCurrent[i][j] = std::complex<double>(0.0, 0.0); }
34 m_electricalData.name = name;
36Transformer::~Transformer() {}
42 if (m_parentList.size() == 0) {
43 m_position = position;
44 m_parentList.push_back(parent);
51 m_pointList.push_back(parentPt);
52 m_pointList.push_back(
GetSwitchPoint(parent, parentPt, m_position));
54 wxRect2DDouble genRect(0, 0, 0, 0);
55 m_switchRect.push_back(genRect);
61 else if (parent != m_parentList[0]) {
62 m_parentList.push_back(parent);
74 m_position = wxPoint2DDouble(
75 (m_pointList[0].m_x + parentPt.m_x) / 2.0,
76 (m_pointList[0].m_y + parentPt.m_y) / 2.0);
80 wxPoint2DDouble term1 =
82 RotateLocal(wxPoint2DDouble(-40.0, 0.0), m_angle);
84 wxPoint2DDouble term2 =
86 RotateLocal(wxPoint2DDouble(40.0, 0.0), m_angle);
88 m_pointList.push_back(term1);
89 m_pointList.push_back(term2);
97 m_pointList.push_back(
103 m_pointList.push_back(parentPt);
106 wxRect2DDouble genRect(0, 0, 0, 0);
107 m_switchRect.push_back(genRect);
110 UpdatePowerFlowArrowsPosition();
116 wxPoint2DDouble p1 = m_pointList[0];
117 wxPoint2DDouble p2 = parentPt;
119 double dx = p2.m_x - p1.m_x;
120 double dy = p2.m_y - p1.m_y;
123 if (std::abs(dy) > std::abs(dx)) {
124 m_angle = (dy >= 0.0) ? 90.0 : 270.0;
127 m_angle = (dx >= 0.0) ? 0.0 : 180.0;
131 m_position = wxPoint2DDouble((p1.m_x + p2.m_x) / 2.0, (p1.m_y + p2.m_y) / 2.0);
134 if (std::abs(dx) < 1.0) {
135 m_position.m_x = p1.m_x;
136 m_position.m_y = std::round(m_position.m_y / 20.0) * 20.0;
138 else if (std::abs(dy) < 1.0) {
139 m_position.m_y = p1.m_y;
140 m_position.m_x = std::round(m_position.m_x / 20.0) * 20.0;
143 m_position.m_x = std::round(m_position.m_x / 20.0) * 20.0;
144 m_position.m_y = std::round(m_position.m_y / 20.0) * 20.0;
155 auto IsPointInsideBus = [](
Element* bus,
const wxPoint2DDouble& point) ->
bool {
156 wxPoint2DDouble delta(
160 wxPoint2DDouble local =
161 bus->RotateLocal(delta, -bus->
GetAngle());
163 double halfWidth = bus->
GetWidth() / 2.0 + 2.0;
164 double halfHeight = bus->
GetHeight() / 2.0 + 2.0;
166 return std::abs(local.m_x) <= halfWidth &&
167 std::abs(local.m_y) <= halfHeight;
170 if (std::abs(dy) > std::abs(dx)) {
173 wxPoint2DDouble candidate1(m_position.m_x, m_parentList[0]->GetPosition().m_y);
175 wxPoint2DDouble candidate2(m_position.m_x, parent->
GetPosition().m_y);
177 if (IsPointInsideBus(m_parentList[0], candidate1) && IsPointInsideBus(parent, candidate2)) {
178 m_pointList[0].m_x = m_position.m_x;
179 parentPt.m_x = m_position.m_x;
185 wxPoint2DDouble candidate1(m_parentList[0]->
GetPosition().m_x, m_position.m_y);
187 wxPoint2DDouble candidate2(parent->
GetPosition().m_x, m_position.m_y);
189 if (IsPointInsideBus(m_parentList[0], candidate1) &&
190 IsPointInsideBus(parent, candidate2)) {
192 m_pointList[0].m_y = m_position.m_y;
193 parentPt.m_y = m_position.m_y;
205 wxPoint2DDouble term1 = m_position + RotateLocal(wxPoint2DDouble(-40.0, 0.0), m_angle);
207 wxPoint2DDouble term2 = m_position + RotateLocal(wxPoint2DDouble(40.0, 0.0), m_angle);
209 term1.m_x = std::round(term1.m_x);
210 term1.m_y = std::round(term1.m_y);
212 term2.m_x = std::round(term2.m_x);
213 term2.m_y = std::round(term2.m_y);
215 m_pointList.push_back(term1);
216 m_pointList.push_back(term2);
219 m_pointList[1] =
GetSwitchPoint(m_parentList[0], m_pointList[0], term1);
224 m_pointList.push_back(parentPt);
227 wxRect2DDouble genRect(0, 0, 0, 0);
228 m_switchRect.push_back(genRect);
231 UpdatePowerFlowArrowsPosition();
243 return m_rect.Contains(ptR);
326 wxColour elementColour;
331 elementColour = guiColour->enabled;
334 elementColour = guiColour->disable;
339 gc->SetPen(wxPen(guiColour->selection, 2 + m_borderSize * 2.0));
340 gc->SetBrush(*wxTRANSPARENT_BRUSH);
341 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
346 gc->Translate(m_position.m_x, m_position.m_y);
347 gc->Rotate(wxDegToRad(m_angle));
348 gc->Translate(-m_position.m_x, -m_position.m_y);
350 gc->SetPen(*wxTRANSPARENT_PEN);
351 gc->SetBrush(wxBrush(guiColour->selection));
352 DrawDCCircle(m_position + wxPoint2DDouble(-15.0, 0.0), 20 + (m_borderSize + 1.5) / scale, 20, gc);
353 DrawDCCircle(m_position + wxPoint2DDouble(15.0, 0.0), 20 + (m_borderSize + 1.5) / scale, 20, gc);
358 gc->SetPen(*wxTRANSPARENT_PEN);
359 gc->SetBrush(wxBrush(guiColour->selection));
360 if (m_pointList.size() > 0) {
361 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc);
362 if (m_inserted) {
DrawDCCircle(m_pointList[m_pointList.size() - 1], 5.0 + m_borderSize / scale, 10, gc); }
368 gc->SetPen(wxPen(elementColour, 2));
369 gc->SetBrush(*wxTRANSPARENT_BRUSH);
370 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
373 gc->SetPen(*wxTRANSPARENT_PEN);
374 gc->SetBrush(wxBrush(elementColour));
375 if (m_pointList.size() > 0) {
377 if (m_inserted) {
DrawDCCircle(m_pointList[m_pointList.size() - 1], 5.0, 10, gc); }
386 gc->Translate(m_position.m_x, m_position.m_y);
387 gc->Rotate(wxDegToRad(m_angle));
388 gc->Translate(-m_position.m_x, -m_position.m_y);
391 gc->SetPen(*wxTRANSPARENT_PEN);
392 gc->SetBrush(wxBrush(guiColour->background));
393 DrawDCCircle(m_position + wxPoint2DDouble(-15.0, 0.0), 20, 20, gc);
394 DrawDCCircle(m_position + wxPoint2DDouble(15.0, 0.0), 20, 20, gc);
396 gc->SetPen(wxPen(elementColour, 2));
397 gc->SetBrush(*wxTRANSPARENT_BRUSH);
398 DrawDCCircle(m_position + wxPoint2DDouble(-15.0, 0.0), 20, 20, gc);
399 DrawDCCircle(m_position + wxPoint2DDouble(15.0, 0.0), 20, 20, gc);
402 gc->SetPen(*wxTRANSPARENT_PEN);
403 gc->SetBrush(wxBrush(elementColour));
409 DrawStabilityEventGC(gc, translation, scale, guiColour);
416 wxColour elementColour;
419 elementColour = guiColour->eventElement;
421 elementColour = guiColour->enabled;
424 elementColour = guiColour->disable;
426 std::vector<wxPoint> pointList;
427 for (
auto& pt : m_pointList) { pointList.emplace_back(
static_cast<int>(pt.m_x),
static_cast<int>(pt.m_y)); }
432 dc.SetPen(wxPen(wxColour(guiColour->selection), 2 + m_borderSize * 2.0));
433 dc.SetBrush(*wxTRANSPARENT_BRUSH);
434 dc.DrawLines(pointList.size(), &pointList[0]);
436 dc.SetPen(*wxTRANSPARENT_PEN);
437 dc.SetBrush(wxBrush(guiColour->selection));
440 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(15.0, 0.0), m_angle), 20 + (m_borderSize + 1.5) / scale, dc);
441 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(-15.0, 0.0), m_angle), 20 + (m_borderSize + 1.5) / scale, dc);
444 dc.SetPen(*wxTRANSPARENT_PEN);
445 dc.SetBrush(wxBrush(guiColour->selection));
446 if (pointList.size() > 0) {
447 DrawDCCircle(pointList[0], 5.0 + m_borderSize / scale, dc);
448 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0 + m_borderSize / scale, dc); }
454 dc.SetPen(wxPen(elementColour, 2));
455 dc.SetBrush(*wxTRANSPARENT_BRUSH);
456 dc.DrawLines(pointList.size(), &pointList[0]);
459 dc.SetPen(*wxTRANSPARENT_PEN);
460 dc.SetBrush(wxBrush(elementColour));
461 if (pointList.size() > 0) {
463 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0, dc); }
469 dc.SetPen(*wxTRANSPARENT_PEN);
470 dc.SetBrush(wxBrush(guiColour->background));
471 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(15.0, 0.0), m_angle), 20, dc);
472 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(-15.0, 0.0), m_angle), 20, dc);
474 dc.SetPen(wxPen(elementColour, 2));
475 dc.SetBrush(*wxTRANSPARENT_BRUSH);
476 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(15.0, 0.0), m_angle), 20, dc);
477 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(-15.0, 0.0), m_angle), 20, dc);
480 dc.SetPen(*wxTRANSPARENT_PEN);
481 dc.SetBrush(wxBrush(elementColour));
482 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(-35, -20), m_angle), 4, dc);
488 if (m_angle == 0.0 || m_angle == 180.0)
return m_rect.Intersects(rect);
494 double rotAngle = m_rotationAngle;
495 if (!clockwise) rotAngle = -m_rotationAngle;
498 while (m_angle >= 360.0) m_angle -= 360.0;
499 while (m_angle < 0.0) m_angle += 360.0;
502 if (std::abs(m_angle - 90.0) < 1e-4) m_angle = 90.0;
503 else if (std::abs(m_angle - 180.0) < 1e-4) m_angle = 180.0;
504 else if (std::abs(m_angle - 270.0) < 1e-4) m_angle = 270.0;
505 else if (std::abs(m_angle - 0.0) < 1e-4 || std::abs(m_angle - 360.0) < 1e-4) m_angle = 0.0;
508 if (m_pointList.size() >= 4) {
509 wxPoint2DDouble t1 = m_position + RotateLocal(wxPoint2DDouble(-40.0, 0.0), m_angle);
510 wxPoint2DDouble t2 = m_position + RotateLocal(wxPoint2DDouble(40.0, 0.0), m_angle);
511 m_pointList[2] = wxPoint2DDouble(std::round(t1.m_x), std::round(t1.m_y));
512 m_pointList[3] = wxPoint2DDouble(std::round(t2.m_x), std::round(t2.m_y));
515 UpdateSwitchesPosition();
516 UpdatePowerFlowArrowsPosition();
524 if (m_pointList.size() >= 4) {
525 wxPoint2DDouble t1 = m_position + RotateLocal(wxPoint2DDouble(-40.0, 0.0), m_angle);
526 wxPoint2DDouble t2 = m_position + RotateLocal(wxPoint2DDouble(40.0, 0.0), m_angle);
527 m_pointList[2] = wxPoint2DDouble(std::round(t1.m_x), std::round(t1.m_y));
528 m_pointList[3] = wxPoint2DDouble(std::round(t2.m_x), std::round(t2.m_y));
531 if (!m_parentList[0]) { m_pointList[0] = m_movePts[0] + position - m_moveStartPt; }
532 if (!m_parentList[1]) {
533 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
536 UpdateSwitchesPosition();
537 UpdatePowerFlowArrowsPosition();
540void Transformer::AlignToGrid(
double gridSize)
546 m_position.m_x = std::round(m_position.m_x / gridSize) * gridSize;
547 m_position.m_y = std::round(m_position.m_y / gridSize) * gridSize;
552 if (m_pointList.size() >= 4) {
553 wxPoint2DDouble t1 = m_position + RotateLocal(wxPoint2DDouble(-40.0, 0.0), m_angle);
554 wxPoint2DDouble t2 = m_position + RotateLocal(wxPoint2DDouble(40.0, 0.0), m_angle);
555 m_pointList[2] = wxPoint2DDouble(std::round(t1.m_x), std::round(t1.m_y));
556 m_pointList[3] = wxPoint2DDouble(std::round(t2.m_x), std::round(t2.m_y));
560 bool isVertical = (std::abs(m_angle - 90.0) < 1.0 || std::abs(m_angle - 270.0) < 1.0);
563 auto IsPointInsideBus =
564 [](
Element* bus,
const wxPoint2DDouble& point) ->
bool
570 wxPoint2DDouble local = bus->RotateLocal(delta, -bus->
GetAngle());
572 double halfWidth = bus->
GetWidth() / 2.0 + 2.0;
573 double halfHeight = bus->
GetHeight() / 2.0 + 2.0;
575 return std::abs(local.m_x) <= halfWidth && std::abs(local.m_y) <= halfHeight;
579 if (m_parentList.size() > 0 && m_parentList[0] && !m_pointList.empty()) {
581 Element* bus1 = m_parentList[0];
586 wxPoint2DDouble candidate(m_position.m_x, bus1->
GetPosition().m_y);
588 if (IsPointInsideBus(bus1, candidate)) {
589 m_pointList[0].m_x = m_position.m_x;
593 m_pointList[0].m_y = std::round(m_pointList[0].m_y / gridSize) * gridSize;
598 wxPoint2DDouble candidate(bus1->
GetPosition().m_x, m_position.m_y);
600 if (IsPointInsideBus(bus1, candidate)) {
601 m_pointList[0].m_y = m_position.m_y;
605 m_pointList[0].m_x = std::round(m_pointList[0].m_x / gridSize) * gridSize;
608 else if (!m_pointList.empty()) {
609 m_pointList[0].m_x = std::round(m_pointList[0].m_x / gridSize) * gridSize;
611 m_pointList[0].m_y = std::round(m_pointList[0].m_y / gridSize) * gridSize;
615 if (m_parentList.size() > 1 &&
617 !m_pointList.empty()) {
619 Element* bus2 = m_parentList[1];
624 wxPoint2DDouble candidate(m_position.m_x, bus2->
GetPosition().m_y);
626 if (IsPointInsideBus(bus2, candidate)) {
627 m_pointList.back().m_x = m_position.m_x;
631 m_pointList.back().m_y = std::round(m_pointList.back().m_y / gridSize) * gridSize;
636 wxPoint2DDouble candidate(bus2->
GetPosition().m_x, m_position.m_y);
638 if (IsPointInsideBus(bus2, candidate)) {
639 m_pointList.back().m_y = m_position.m_y;
643 m_pointList.back().m_x = std::round(m_pointList.back().m_x / gridSize) * gridSize;
646 else if (m_pointList.size() > 1) {
647 m_pointList.back().m_x = std::round(m_pointList.back().m_x / gridSize) * gridSize;
649 m_pointList.back().m_y = std::round(m_pointList.back().m_y / gridSize) * gridSize;
652 UpdateSwitchesPosition();
653 UpdatePowerFlowArrowsPosition();
660 if (parent == m_parentList[0]) {
661 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
664 else if (parent == m_parentList[1]) {
665 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
669 if (m_activeNodeID == 1) {
670 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
671 if (m_parentList[0]) {
672 m_parentList[0]->RemoveChild(
this);
673 m_parentList[0] =
nullptr;
677 else if (m_activeNodeID == 2) {
678 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
679 if (m_parentList[1]) {
680 m_parentList[1]->RemoveChild(
this);
681 m_parentList[1] =
nullptr;
688 UpdateSwitchesPosition();
689 UpdatePowerFlowArrowsPosition();
694 m_moveStartPt = position;
695 m_movePts = m_pointList;
696 m_movePos = m_position;
703 wxString busName[2] = {
"?",
"?" };
704 if (m_parentList.size() == 2) {
706 for (
Element* element : m_parentList) {
708 Bus* bus =
static_cast<Bus*
>(element);
709 busName[i] = bus->GetElectricalData().name;
715 wxMenu* textMenu =
new wxMenu();
717 textMenu->Append(ID_TXT_NAME, _(
"Name"));
718 textMenu->Append(ID_TXT_BRANCH_ACTIVE_POWER_1_2, _(
"Active power (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
719 textMenu->Append(ID_TXT_BRANCH_ACTIVE_POWER_2_1, _(
"Active power (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
720 textMenu->Append(ID_TXT_BRANCH_REACTIVE_POWER_1_2, _(
"Reactive power (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
721 textMenu->Append(ID_TXT_BRANCH_REACTIVE_POWER_2_1, _(
"Reactive power (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
722 textMenu->Append(ID_TXT_BRANCH_LOSSES, _(
"Losses"));
723 textMenu->Append(ID_TXT_BRANCH_CURRENT_1_2, _(
"Current (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
724 textMenu->Append(ID_TXT_BRANCH_CURRENT_2_1, _(
"Current (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
725 textMenu->Append(ID_TXT_BRANCH_FAULT_CURRENT_1_2, _(
"Fault current (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
726 textMenu->Append(ID_TXT_BRANCH_FAULT_CURRENT_2_1, _(
"Fault current (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
727 textMenu->Append(ID_TXT_TAP, _(
"Tap"));
728 textMenu->SetClientData(menu.GetClientData());
729 menu.AppendSubMenu(textMenu, _(
"Add text"));
738 transfForm.CenterOnParent();
739 if (transfForm.ShowModal() == wxID_OK) {
747 if (nominalVoltage.size() == 1) {
748 m_electricalData.primaryNominalVoltage = nominalVoltage[0];
749 m_electricalData.primaryNominalVoltageUnit = nominalVoltageUnit[0];
751 else if (nominalVoltage.size() == 2) {
752 m_electricalData.primaryNominalVoltage = nominalVoltage[0];
753 m_electricalData.primaryNominalVoltageUnit = nominalVoltageUnit[0];
754 m_electricalData.secondaryNominalVoltage = nominalVoltage[1];
755 m_electricalData.secondaryNominalVoltageUnit = nominalVoltageUnit[1];
759void Transformer::UpdatePowerFlowArrowsPosition()
761 std::vector<wxPoint2DDouble> edges;
762 switch (m_pfDirection) {
764 m_powerFlowArrow.clear();
767 for (
int i = 1; i < (int)m_pointList.size() - 1; i++) { edges.push_back(m_pointList[i]); }
770 for (
int i = (
int)m_pointList.size() - 2; i > 0; i--) { edges.push_back(m_pointList[i]); }
780 double rotAngle = m_rotationAngle;
781 if (!clockwise) rotAngle = -m_rotationAngle;
783 if (parent == m_parentList[0]) {
786 else if (parent == m_parentList[1]) {
787 m_pointList[m_pointList.size() - 1] = parent->
RotateAtPosition(m_pointList[m_pointList.size() - 1], rotAngle);
789 UpdateSwitchesPosition();
790 UpdatePowerFlowArrowsPosition();
795 if (m_activeNodeID == 1 && parent == m_parentList[0])
return false;
796 if (m_activeNodeID == 2 && parent == m_parentList[1])
return false;
798 if (parent && m_activeNodeID != 0) {
799 wxRect2DDouble nodeRect(0, 0, 0, 0);
800 if (m_activeNodeID == 1) {
801 nodeRect = wxRect2DDouble(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
802 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
804 if (m_activeNodeID == 2) {
805 nodeRect = wxRect2DDouble(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
806 m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize,
807 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
811 if (m_activeNodeID == 1) {
813 if (m_parentList[1] == parent) {
818 m_parentList[0] = parent;
822 m_pointList[0], -parent->
GetAngle());
825 m_pointList[0] = parentPt;
827 UpdateSwitchesPosition();
828 UpdatePowerFlowArrowsPosition();
831 if (m_activeNodeID == 2) {
832 if (m_parentList[0] == parent) {
837 m_parentList[1] = parent;
839 wxPoint2DDouble parentPt =
843 m_pointList[m_pointList.size() - 1] = parentPt;
845 UpdateSwitchesPosition();
846 UpdatePowerFlowArrowsPosition();
851 if (m_activeNodeID == 1) m_parentList[0] =
nullptr;
852 if (m_activeNodeID == 2) m_parentList[1] =
nullptr;
860 m_pfDirection = pfDirection;
861 UpdatePowerFlowArrowsPosition();
873 wxString tipText = m_electricalData.name;
874 wxString primVoltage =
StringFromDouble(m_electricalData.primaryNominalVoltage);
875 switch (m_electricalData.primaryNominalVoltageUnit) {
876 case ElectricalUnit::UNIT_V: {
877 primVoltage += _(
" V");
879 case ElectricalUnit::UNIT_kV: {
880 primVoltage += _(
" kV");
885 wxString secVoltage =
StringFromDouble(m_electricalData.secondaryNominalVoltage);
886 switch (m_electricalData.secondaryNominalVoltageUnit) {
887 case ElectricalUnit::UNIT_V: {
888 secVoltage += _(
" V");
890 case ElectricalUnit::UNIT_kV: {
891 secVoltage += _(
" kV");
897 tipText +=
"\n" + primVoltage +
" / " + secVoltage;
902 busNumber[0] =
static_cast<Bus*
>(m_parentList[0])->GetElectricalData().number + 1;
903 busNumber[1] =
static_cast<Bus*
>(m_parentList[1])->GetElectricalData().number + 1;
905 tipText += _(
"\nP") + wxString::Format(
"(%d-%d) = ", busNumber[0], busNumber[1]) +
906 wxString::FromDouble(m_electricalData.powerFlow[0].real(), 5) + _(
" p.u.");
907 tipText += _(
"\nQ") + wxString::Format(
"(%d-%d) = ", busNumber[0], busNumber[1]) +
908 wxString::FromDouble(m_electricalData.powerFlow[0].imag(), 5) + _(
" p.u.");
909 tipText += _(
"\nP") + wxString::Format(
"(%d-%d) = ", busNumber[1], busNumber[0]) +
910 wxString::FromDouble(m_electricalData.powerFlow[1].real(), 5) + _(
" p.u.");
911 tipText += _(
"\nQ") + wxString::Format(
"(%d-%d) = ", busNumber[1], busNumber[0]) +
912 wxString::FromDouble(m_electricalData.powerFlow[1].imag(), 5) + _(
" p.u.");
914 if (m_electricalData.hasTapChanger) {
915 tipText += _(
"\nOLTC: Enabled (Vset = ") +
916 wxString::FromDouble(m_electricalData.oltcTargetVoltage, 3) +
918 wxString::FromDouble(m_electricalData.turnsRatio, 4) +
922 if (!m_electricalData.harmonicOrder.empty()) {
923 tipText += _(
"\n\nHarmonic currents:");
925 for (
auto& hCurrent1 : m_electricalData.harmonicCurrent[0]) {
926 auto& hCurrent2 = m_electricalData.harmonicCurrent[1][i];
928 i1.Printf(_(
"\nIh(%d)(%d-%d) = %.5e%s%.2f%s p.u."), m_electricalData.harmonicOrder[i], busNumber[0], busNumber[1], std::abs(hCurrent1), wxString(L
'\u2220'), wxRadToDeg(std::arg(hCurrent1)), wxString(L
'\u00B0'));
929 i2.Printf(_(
"\nIh(%d)(%d-%d) = %.5e%s%.2f%s p.u."), m_electricalData.harmonicOrder[i], busNumber[1], busNumber[0], std::abs(hCurrent2), wxString(L
'\u2220'), wxRadToDeg(std::arg(hCurrent2)), wxString(L
'\u00B0'));
944 data.name = m_electricalData.name;
946 data.nominalPower = m_electricalData.nominalPower;
947 data.nominalPowerUnit = m_electricalData.nominalPowerUnit;
949 data.primaryNominalVoltage = m_electricalData.primaryNominalVoltage;
950 data.primaryNominalVoltageUnit = m_electricalData.primaryNominalVoltageUnit;
952 data.secondaryNominalVoltage = m_electricalData.secondaryNominalVoltage;
953 data.secondaryNominalVoltageUnit = m_electricalData.secondaryNominalVoltageUnit;
955 data.useTransformerPower = m_electricalData.useTransformerPower;
957 data.baseVoltage = m_electricalData.baseVoltage;
959 data.resistance = m_electricalData.resistance;
960 data.resistanceUnit = m_electricalData.resistanceUnit;
962 data.indReactance = m_electricalData.indReactance;
963 data.indReactanceUnit = m_electricalData.indReactanceUnit;
965 data.connection = m_electricalData.connection;
966 data.turnsRatio = m_electricalData.turnsRatio;
967 data.phaseShift = m_electricalData.phaseShift;
969 data.hasTapChanger = m_electricalData.hasTapChanger;
970 data.nominalTurnsRatio = m_electricalData.nominalTurnsRatio;
971 data.oltcControlledBus = m_electricalData.oltcControlledBus;
972 data.oltcTargetVoltage = m_electricalData.oltcTargetVoltage;
973 data.oltcVoltageDeadband = m_electricalData.oltcVoltageDeadband;
974 data.oltcMinTap = m_electricalData.oltcMinTap;
975 data.oltcMaxTap = m_electricalData.oltcMaxTap;
976 data.oltcTapStep = m_electricalData.oltcTapStep;
977 data.oltcIsDiscrete = m_electricalData.oltcIsDiscrete;
979 data.zeroResistance = m_electricalData.zeroResistance;
980 data.zeroIndReactance = m_electricalData.zeroIndReactance;
982 data.primaryGrndResistance = m_electricalData.primaryGrndResistance;
983 data.primaryGrndReactance = m_electricalData.primaryGrndReactance;
985 data.secondaryGrndResistance = m_electricalData.secondaryGrndResistance;
986 data.secondaryGrndReactance = m_electricalData.secondaryGrndReactance;
988 data.powerFlow[0] = m_electricalData.powerFlow[0];
989 data.powerFlow[1] = m_electricalData.powerFlow[1];
991 data.faultCurrent[0][0] = m_electricalData.faultCurrent[0][0];
992 data.faultCurrent[0][1] = m_electricalData.faultCurrent[0][1];
993 data.faultCurrent[0][2] = m_electricalData.faultCurrent[0][2];
994 data.faultCurrent[1][0] = m_electricalData.faultCurrent[1][0];
995 data.faultCurrent[1][1] = m_electricalData.faultCurrent[1][1];
996 data.faultCurrent[1][2] = m_electricalData.faultCurrent[1][2];
999 data.harmonicOrder = m_electricalData.harmonicOrder;
1000 data.harmonicCurrent[0] = m_electricalData.harmonicCurrent[0];
1001 data.harmonicCurrent[1] = m_electricalData.harmonicCurrent[1];
1003 double transformerBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
1004 double baseVoltage = 0.0;
1005 if (data.baseVoltage == 0) {
1006 baseVoltage = GetValueFromUnit(data.primaryNominalVoltage, data.primaryNominalVoltageUnit);
1009 baseVoltage = GetValueFromUnit(data.secondaryNominalVoltage, data.secondaryNominalVoltageUnit);
1011 double systemBaseImpedance = (baseVoltage * baseVoltage) / systemBasePower;
1012 double transformerBaseImpedance = (baseVoltage * baseVoltage) / transformerBasePower;
1015 double r = data.resistance;
1016 if (data.resistanceUnit == ElectricalUnit::UNIT_PU) {
1017 if (data.useTransformerPower) data.resistance = (r * transformerBaseImpedance) / systemBaseImpedance;
1020 data.resistance = r / systemBaseImpedance;
1022 data.resistanceUnit = ElectricalUnit::UNIT_PU;
1025 double x = data.indReactance;
1026 if (data.indReactanceUnit == ElectricalUnit::UNIT_PU) {
1027 if (data.useTransformerPower) data.indReactance = (x * transformerBaseImpedance) / systemBaseImpedance;
1030 data.indReactance = x / systemBaseImpedance;
1032 data.indReactanceUnit = ElectricalUnit::UNIT_PU;
1037 double r0 = data.zeroResistance;
1038 if (data.useTransformerPower) data.zeroResistance = (r0 * transformerBaseImpedance) / systemBaseImpedance;
1041 double x0 = data.zeroIndReactance;
1042 if (data.useTransformerPower) data.zeroIndReactance = (x0 * transformerBaseImpedance) / systemBaseImpedance;
1045 double rgp = data.primaryGrndResistance;
1046 if (data.useTransformerPower) data.primaryGrndResistance = (rgp * transformerBaseImpedance) / systemBaseImpedance;
1049 double xgp = data.primaryGrndReactance;
1050 if (data.useTransformerPower) data.primaryGrndReactance = (xgp * transformerBaseImpedance) / systemBaseImpedance;
1053 double rgs = data.secondaryGrndResistance;
1054 if (data.useTransformerPower) data.secondaryGrndResistance = (rgs * transformerBaseImpedance) / systemBaseImpedance;
1057 double xgs = data.secondaryGrndReactance;
1058 if (data.useTransformerPower) data.secondaryGrndReactance = (xgs * transformerBaseImpedance) / systemBaseImpedance;
1061 data.powerFlow[0] = std::complex<double>(0, 0);
1062 data.powerFlow[1] = std::complex<double>(0, 0);
1063 data.faultCurrent[0][0] = std::complex<double>(0, 0);
1064 data.faultCurrent[0][1] = std::complex<double>(0, 0);
1065 data.faultCurrent[0][2] = std::complex<double>(0, 0);
1066 data.faultCurrent[1][0] = std::complex<double>(0, 0);
1067 data.faultCurrent[1][1] = std::complex<double>(0, 0);
1068 data.faultCurrent[1][2] = std::complex<double>(0, 0);
1074rapidxml::xml_node<>* Transformer::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
1076 auto elementNode = XMLParser::AppendNode(doc, elementListNode,
"Transfomer");
1077 XMLParser::SetNodeAttribute(doc, elementNode,
"ID", m_elementID);
1078 auto cadProp = XMLParser::AppendNode(doc, elementNode,
"CADProperties");
1079 auto position = XMLParser::AppendNode(doc, cadProp,
"Position");
1080 auto posX = XMLParser::AppendNode(doc, position,
"X");
1081 XMLParser::SetNodeValue(doc, posX, m_position.m_x);
1082 auto posY = XMLParser::AppendNode(doc, position,
"Y");
1083 XMLParser::SetNodeValue(doc, posY, m_position.m_y);
1084 auto size = XMLParser::AppendNode(doc, cadProp,
"Size");
1085 auto width = XMLParser::AppendNode(doc, size,
"Width");
1086 XMLParser::SetNodeValue(doc, width, m_width);
1087 auto height = XMLParser::AppendNode(doc, size,
"Height");
1088 XMLParser::SetNodeValue(doc, height, m_height);
1089 auto angle = XMLParser::AppendNode(doc, cadProp,
"Angle");
1090 XMLParser::SetNodeValue(doc, angle, m_angle);
1091 auto nodeList = XMLParser::AppendNode(doc, cadProp,
"NodeList");
1092 auto nodePos1 = XMLParser::AppendNode(doc, nodeList,
"Node");
1093 XMLParser::SetNodeAttribute(doc, nodePos1,
"ID", 0);
1094 auto nodePosX1 = XMLParser::AppendNode(doc, nodePos1,
"X");
1095 XMLParser::SetNodeValue(doc, nodePosX1, m_pointList[0].m_x);
1096 auto nodePosY1 = XMLParser::AppendNode(doc, nodePos1,
"Y");
1097 XMLParser::SetNodeValue(doc, nodePosY1, m_pointList[0].m_y);
1098 auto nodePos2 = XMLParser::AppendNode(doc, nodeList,
"Node");
1099 XMLParser::SetNodeAttribute(doc, nodePos2,
"ID", 1);
1100 auto nodePosX2 = XMLParser::AppendNode(doc, nodePos2,
"X");
1101 XMLParser::SetNodeValue(doc, nodePosX2, m_pointList[m_pointList.size() - 1].m_x);
1102 auto nodePosY2 = XMLParser::AppendNode(doc, nodePos2,
"Y");
1103 XMLParser::SetNodeValue(doc, nodePosY2, m_pointList[m_pointList.size() - 1].m_y);
1105 auto parentIDList = XMLParser::AppendNode(doc, cadProp,
"ParentIDList");
1106 for (
unsigned int i = 0; i < m_parentList.size(); i++) {
1107 Element* parent = m_parentList[i];
1109 auto parentID = XMLParser::AppendNode(doc, parentIDList,
"ParentID");
1110 XMLParser::SetNodeAttribute(doc, parentID,
"ID",
static_cast<int>(i));
1111 XMLParser::SetNodeValue(doc, parentID, parent->
GetID());
1115 auto electricalProp = XMLParser::AppendNode(doc, elementNode,
"ElectricalProperties");
1116 auto isOnline = XMLParser::AppendNode(doc, electricalProp,
"IsOnline");
1117 XMLParser::SetNodeValue(doc, isOnline, m_online);
1118 auto name = XMLParser::AppendNode(doc, electricalProp,
"Name");
1119 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
1120 auto primaryNominalVoltage = XMLParser::AppendNode(doc, electricalProp,
"PrimaryNominalVoltage");
1121 XMLParser::SetNodeValue(doc, primaryNominalVoltage, m_electricalData.primaryNominalVoltage);
1122 XMLParser::SetNodeAttribute(doc, primaryNominalVoltage,
"UnitID",
static_cast<int>(m_electricalData.primaryNominalVoltageUnit));
1123 auto secondaryNominalVoltage = XMLParser::AppendNode(doc, electricalProp,
"SecondaryNominalVoltage");
1124 XMLParser::SetNodeValue(doc, secondaryNominalVoltage, m_electricalData.secondaryNominalVoltage);
1125 XMLParser::SetNodeAttribute(doc, secondaryNominalVoltage,
"UnitID",
static_cast<int>(m_electricalData.secondaryNominalVoltageUnit));
1126 auto nominalPower = XMLParser::AppendNode(doc, electricalProp,
"NominalPower");
1127 XMLParser::SetNodeValue(doc, nominalPower, m_electricalData.nominalPower);
1128 XMLParser::SetNodeAttribute(doc, nominalPower,
"UnitID",
static_cast<int>(m_electricalData.nominalPowerUnit));
1129 auto resistance = XMLParser::AppendNode(doc, electricalProp,
"Resistance");
1130 XMLParser::SetNodeValue(doc, resistance, m_electricalData.resistance);
1131 XMLParser::SetNodeAttribute(doc, resistance,
"UnitID",
static_cast<int>(m_electricalData.resistanceUnit));
1132 auto indReactance = XMLParser::AppendNode(doc, electricalProp,
"IndReactance");
1133 XMLParser::SetNodeValue(doc, indReactance, m_electricalData.indReactance);
1134 XMLParser::SetNodeAttribute(doc, indReactance,
"UnitID",
static_cast<int>(m_electricalData.indReactanceUnit));
1135 auto connection = XMLParser::AppendNode(doc, electricalProp,
"Connection");
1136 XMLParser::SetNodeValue(doc, connection, m_electricalData.connection);
1137 auto turnsRatio = XMLParser::AppendNode(doc, electricalProp,
"TurnsRatio");
1138 XMLParser::SetNodeValue(doc, turnsRatio, m_electricalData.turnsRatio);
1139 auto phaseShift = XMLParser::AppendNode(doc, electricalProp,
"PhaseShift");
1140 XMLParser::SetNodeValue(doc, phaseShift, m_electricalData.phaseShift);
1141 auto useTransformerPower = XMLParser::AppendNode(doc, electricalProp,
"UseTransfomerPower");
1142 XMLParser::SetNodeValue(doc, useTransformerPower, m_electricalData.useTransformerPower);
1144 auto oltcNode = XMLParser::AppendNode(doc, electricalProp,
"TapChanger");
1145 auto hasTapChanger = XMLParser::AppendNode(doc, oltcNode,
"Enabled");
1146 XMLParser::SetNodeValue(doc, hasTapChanger, m_electricalData.hasTapChanger ? 1 : 0);
1147 auto nominalTurnsRatio = XMLParser::AppendNode(doc, oltcNode,
"NominalTurnsRatio");
1148 XMLParser::SetNodeValue(doc, nominalTurnsRatio, m_electricalData.nominalTurnsRatio);
1149 auto oltcControlledBus = XMLParser::AppendNode(doc, oltcNode,
"ControlledBus");
1150 XMLParser::SetNodeValue(doc, oltcControlledBus, m_electricalData.oltcControlledBus);
1151 auto oltcTargetVoltage = XMLParser::AppendNode(doc, oltcNode,
"TargetVoltage");
1152 XMLParser::SetNodeValue(doc, oltcTargetVoltage, m_electricalData.oltcTargetVoltage);
1153 auto oltcVoltageDeadband = XMLParser::AppendNode(doc, oltcNode,
"VoltageDeadband");
1154 XMLParser::SetNodeValue(doc, oltcVoltageDeadband, m_electricalData.oltcVoltageDeadband);
1155 auto oltcMinTap = XMLParser::AppendNode(doc, oltcNode,
"MinTap");
1156 XMLParser::SetNodeValue(doc, oltcMinTap, m_electricalData.oltcMinTap);
1157 auto oltcMaxTap = XMLParser::AppendNode(doc, oltcNode,
"MaxTap");
1158 XMLParser::SetNodeValue(doc, oltcMaxTap, m_electricalData.oltcMaxTap);
1159 auto oltcTapStep = XMLParser::AppendNode(doc, oltcNode,
"TapStep");
1160 XMLParser::SetNodeValue(doc, oltcTapStep, m_electricalData.oltcTapStep);
1161 auto oltcIsDiscrete = XMLParser::AppendNode(doc, oltcNode,
"IsDiscrete");
1162 XMLParser::SetNodeValue(doc, oltcIsDiscrete, m_electricalData.oltcIsDiscrete ? 1 : 0);
1164 auto fault = XMLParser::AppendNode(doc, electricalProp,
"Fault");
1165 auto zeroResistance = XMLParser::AppendNode(doc, fault,
"ZeroResistance");
1166 XMLParser::SetNodeValue(doc, zeroResistance, m_electricalData.zeroResistance);
1167 auto zeroIndReactance = XMLParser::AppendNode(doc, fault,
"ZeroIndReactance");
1168 XMLParser::SetNodeValue(doc, zeroIndReactance, m_electricalData.zeroIndReactance);
1169 auto primaryGrndResistance = XMLParser::AppendNode(doc, fault,
"PrimaryGrndResistance");
1170 XMLParser::SetNodeValue(doc, primaryGrndResistance, m_electricalData.primaryGrndResistance);
1171 auto primaryGrndReactance = XMLParser::AppendNode(doc, fault,
"PrimaryGrndReactance");
1172 XMLParser::SetNodeValue(doc, primaryGrndReactance, m_electricalData.primaryGrndReactance);
1173 auto secondaryGrndResistance = XMLParser::AppendNode(doc, fault,
"SecondaryGrndResistance");
1174 XMLParser::SetNodeValue(doc, secondaryGrndResistance, m_electricalData.secondaryGrndResistance);
1175 auto secondaryGrndReactance = XMLParser::AppendNode(doc, fault,
"SecondaryGrndReactance");
1176 XMLParser::SetNodeValue(doc, secondaryGrndReactance, m_electricalData.secondaryGrndReactance);
1178 SaveSwitchingData(doc, electricalProp);
1183bool Transformer::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
1185 auto cadPropNode = elementNode->first_node(
"CADProperties");
1186 if (!cadPropNode)
return false;
1188 auto position = cadPropNode->first_node(
"Position");
1189 double posX = XMLParser::GetNodeValueDouble(position,
"X");
1190 double posY = XMLParser::GetNodeValueDouble(position,
"Y");
1191 auto size = cadPropNode->first_node(
"Size");
1192 m_width = XMLParser::GetNodeValueDouble(size,
"Width");
1193 m_height = XMLParser::GetNodeValueDouble(size,
"Height");
1194 m_angle = XMLParser::GetNodeValueDouble(cadPropNode,
"Angle");
1197 std::vector<wxPoint2DDouble> ptsList;
1198 auto nodePosList = cadPropNode->first_node(
"NodeList");
1199 if (!nodePosList)
return false;
1200 auto nodePos = nodePosList->first_node(
"Node");
1202 double nodePosX = XMLParser::GetNodeValueDouble(nodePos,
"X");
1203 double nodePosY = XMLParser::GetNodeValueDouble(nodePos,
"Y");
1204 ptsList.push_back(wxPoint2DDouble(nodePosX, nodePosY));
1205 nodePos = nodePos->next_sibling(
"Node");
1209 auto parentIDList = cadPropNode->first_node(
"ParentIDList");
1210 if (!parentIDList)
return false;
1211 auto parentNode = parentIDList->first_node(
"ParentID");
1212 long parentID[2] = { -1, -1 };
1213 while (parentNode) {
1215 wxString(parentNode->first_attribute(
"ID")->value()).ToLong(&index);
1216 wxString(parentNode->value()).ToCLong(&parentID[index]);
1217 parentNode = parentNode->next_sibling(
"ParentID");
1220 std::vector<wxPoint2DDouble> nodePtsList;
1221 nodePtsList.push_back(ptsList[0]);
1222 nodePtsList.push_back(ptsList[ptsList.size() - 1]);
1225 std::vector<Bus*> dummyBusList;
1227 for (
unsigned int i = 0; i < 2; ++i) {
1228 if (parentID[i] == -1)
1230 Bus* dummyBus =
new Bus(nodePtsList[i]);
1231 dummyBusList.push_back(dummyBus);
1232 AddParent(dummyBus, nodePtsList[i],
true);
1235 AddParent(parentList[parentID[i]], nodePtsList[i],
true);
1240 Move(wxPoint2DDouble(posX, posY));
1243 for (
auto it = dummyBusList.begin(), itEnd = dummyBusList.end(); it != itEnd; ++it) {
1247 dummyBusList.clear();
1258 auto electricalProp = elementNode->first_node(
"ElectricalProperties");
1259 if (!electricalProp)
return false;
1261 SetOnline(XMLParser::GetNodeValueInt(electricalProp,
"IsOnline"));
1262 m_electricalData.name = electricalProp->first_node(
"Name")->value();
1263 m_electricalData.primaryNominalVoltage = XMLParser::GetNodeValueDouble(electricalProp,
"PrimaryNominalVoltage");
1264 m_electricalData.primaryNominalVoltageUnit =
1265 static_cast<ElectricalUnit
>(XMLParser::GetAttributeValueInt(electricalProp,
"PrimaryNominalVoltage",
"UnitID"));
1266 m_electricalData.secondaryNominalVoltage = XMLParser::GetNodeValueDouble(electricalProp,
"SecondaryNominalVoltage");
1267 m_electricalData.secondaryNominalVoltageUnit =
static_cast<ElectricalUnit
>(
1268 XMLParser::GetAttributeValueInt(electricalProp,
"SecondaryNominalVoltage",
"UnitID"));
1269 m_electricalData.nominalPower = XMLParser::GetNodeValueDouble(electricalProp,
"NominalPower");
1270 m_electricalData.nominalPowerUnit =
1271 static_cast<ElectricalUnit
>(XMLParser::GetAttributeValueInt(electricalProp,
"NominalPower",
"UnitID"));
1272 m_electricalData.resistance = XMLParser::GetNodeValueDouble(electricalProp,
"Resistance");
1273 m_electricalData.resistanceUnit =
1274 static_cast<ElectricalUnit
>(XMLParser::GetAttributeValueInt(electricalProp,
"Resistance",
"UnitID"));
1275 m_electricalData.indReactance = XMLParser::GetNodeValueDouble(electricalProp,
"IndReactance");
1276 m_electricalData.indReactanceUnit =
1277 static_cast<ElectricalUnit
>(XMLParser::GetAttributeValueInt(electricalProp,
"IndReactance",
"UnitID"));
1278 m_electricalData.connection = (TransformerConnection)XMLParser::GetNodeValueInt(electricalProp,
"Connection");
1279 m_electricalData.turnsRatio = XMLParser::GetNodeValueDouble(electricalProp,
"TurnsRatio");
1280 m_electricalData.phaseShift = XMLParser::GetNodeValueDouble(electricalProp,
"PhaseShift");
1281 m_electricalData.useTransformerPower = XMLParser::GetNodeValueInt(electricalProp,
"UseTransfomerPower");
1283 auto oltcNode = electricalProp->first_node(
"TapChanger");
1285 m_electricalData.hasTapChanger = XMLParser::GetNodeValueInt(oltcNode,
"Enabled") == 1;
1286 auto nomNode = oltcNode->first_node(
"NominalTurnsRatio");
1287 if (nomNode) wxString(nomNode->value()).ToCDouble(&m_electricalData.nominalTurnsRatio);
1288 else m_electricalData.nominalTurnsRatio = m_electricalData.turnsRatio;
1289 auto ctrlBusNode = oltcNode->first_node(
"ControlledBus");
1292 wxString(ctrlBusNode->value()).ToCLong(&cb);
1293 m_electricalData.oltcControlledBus = (int)cb;
1295 auto targetVNode = oltcNode->first_node(
"TargetVoltage");
1296 if (targetVNode) wxString(targetVNode->value()).ToCDouble(&m_electricalData.oltcTargetVoltage);
1297 auto deadbandNode = oltcNode->first_node(
"VoltageDeadband");
1298 if (deadbandNode) wxString(deadbandNode->value()).ToCDouble(&m_electricalData.oltcVoltageDeadband);
1299 auto minTapNode = oltcNode->first_node(
"MinTap");
1300 if (minTapNode) wxString(minTapNode->value()).ToCDouble(&m_electricalData.oltcMinTap);
1301 auto maxTapNode = oltcNode->first_node(
"MaxTap");
1302 if (maxTapNode) wxString(maxTapNode->value()).ToCDouble(&m_electricalData.oltcMaxTap);
1303 auto tapStepNode = oltcNode->first_node(
"TapStep");
1304 if (tapStepNode) wxString(tapStepNode->value()).ToCDouble(&m_electricalData.oltcTapStep);
1305 m_electricalData.oltcIsDiscrete = XMLParser::GetNodeValueInt(oltcNode,
"IsDiscrete") == 1;
1308 m_electricalData.hasTapChanger =
false;
1309 m_electricalData.nominalTurnsRatio = m_electricalData.turnsRatio;
1310 m_electricalData.oltcControlledBus = 1;
1311 m_electricalData.oltcTargetVoltage = 1.0;
1312 m_electricalData.oltcVoltageDeadband = 0.005;
1313 m_electricalData.oltcMinTap = 0.90;
1314 m_electricalData.oltcMaxTap = 1.10;
1315 m_electricalData.oltcTapStep = 0.00625;
1316 m_electricalData.oltcIsDiscrete =
false;
1319 auto fault = electricalProp->first_node(
"Fault");
1320 m_electricalData.zeroResistance = XMLParser::GetNodeValueDouble(fault,
"ZeroResistance");
1321 m_electricalData.zeroIndReactance = XMLParser::GetNodeValueDouble(fault,
"ZeroIndReactance");
1322 m_electricalData.primaryGrndResistance = XMLParser::GetNodeValueDouble(fault,
"PrimaryGrndResistance");
1323 m_electricalData.primaryGrndReactance = XMLParser::GetNodeValueDouble(fault,
"PrimaryGrndReactance");
1324 m_electricalData.secondaryGrndResistance = XMLParser::GetNodeValueDouble(fault,
"SecondaryGrndResistance");
1325 m_electricalData.secondaryGrndReactance = XMLParser::GetNodeValueDouble(fault,
"SecondaryGrndReactance");
1327 if (!OpenSwitchingData(electricalProp))
return false;
1333void Transformer::SetBestPositionAndRotation()
1335 wxPoint2DDouble p1 = m_pointList[0];
1336 wxPoint2DDouble p2 = m_pointList[m_pointList.size() - 1];
1337 double dx = p2.m_x - p1.m_x;
1338 double dy = p2.m_y - p1.m_y;
1340 if (std::abs(dy) > std::abs(dx)) {
1341 m_angle = (dy >= 0.0) ? 90.0 : 270.0;
1344 m_angle = (dx >= 0.0) ? 0.0 : 180.0;
1347 wxPoint2DDouble mid = (p1 + p2) / 2.0;
1348 if (std::abs(dx) < 1.0) {
1350 mid.m_y = std::round(mid.m_y / 20.0) * 20.0;
1352 else if (std::abs(dy) < 1.0) {
1354 mid.m_x = std::round(mid.m_x / 20.0) * 20.0;
1357 mid.m_x = std::round(mid.m_x / 20.0) * 20.0;
1358 mid.m_y = std::round(mid.m_y / 20.0) * 20.0;
1363 if (m_parentList.size() > 0 && m_parentList[0] && m_parentList.size() > 1 && m_parentList[1]) {
1364 Element* bus1 = m_parentList[0];
1365 Element* bus2 = m_parentList[1];
1366 if (std::abs(dy) > std::abs(dx)) {
1369 double halfW1 = bus1->
GetWidth() / 2.0 + 2.0;
1370 double halfW2 = bus2->
GetWidth() / 2.0 + 2.0;
1371 if (std::abs(loc1.m_x - bus1->
GetPosition().m_x) <= halfW1 &&
1372 std::abs(loc2.m_x - bus2->
GetPosition().m_x) <= halfW2) {
1373 m_pointList[0].m_x = m_position.m_x;
1374 m_pointList.back().m_x = m_position.m_x;
1380 double halfW1 = bus1->
GetWidth() / 2.0 + 2.0;
1381 double halfW2 = bus2->
GetWidth() / 2.0 + 2.0;
1382 if (std::abs(loc1.m_x - bus1->
GetPosition().m_x) <= halfW1 &&
1383 std::abs(loc2.m_x - bus2->
GetPosition().m_x) <= halfW2) {
1384 m_pointList[0].m_y = m_position.m_y;
1385 m_pointList.back().m_y = m_position.m_y;
1390 if (m_pointList.size() >= 4) {
1391 wxPoint2DDouble t1 = m_position + RotateLocal(wxPoint2DDouble(-40.0, 0.0), m_angle);
1392 wxPoint2DDouble t2 = m_position + RotateLocal(wxPoint2DDouble(40.0, 0.0), m_angle);
1393 m_pointList[2] = wxPoint2DDouble(std::round(t1.m_x), std::round(t1.m_y));
1394 m_pointList[3] = wxPoint2DDouble(std::round(t2.m_x), std::round(t2.m_y));
1396 UpdateSwitchesPosition();
1397 UpdatePowerFlowArrowsPosition();
PowerFlowDirection
Direction of power flow arrows.
Abstract class for branch power elements.
virtual void UpdateSwitches()
Update the switch position.
virtual void RemoveParent(Element *parent)
Remove a parent.
Node for power elements. All others power elements are connected through this.
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
virtual bool RotatedRectanglesIntersects(wxRect2DDouble rect1, wxRect2DDouble rect2, double angle1, double angle2) const
Check if two roteted rectangles intersect.
virtual bool Intersects(wxRect2DDouble rect) const =0
Check if the element's rect intersects other rect.
virtual int GetID() const
Get the element ID.
double GetWidth() const
Get the element width.
virtual void GeneralMenuItens(wxMenu &menu)
Insert general itens to context menu.
wxPoint2DDouble GetPosition() const
Get the element position.
double GetAngle() const
Get the element angle.
double GetHeight() const
Get the element height.
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
virtual void AddChild(Element *child)
Add a child to the child list.
static wxString StringFromDouble(double value, int minDecimal=1, int maxDecimals=13)
Convert a double value to string.
bool SetOnline(bool online=true)
Set if the element is online or offline.
virtual void DrawDCCircle(wxPoint2DDouble position, double radius, int numSegments, wxGraphicsContext *gc) const
Draw a circle using device context.
virtual void SetDynamicEvent(bool dynEvent=true)
Set if the power element have dynamic event.
virtual void CalculatePowerFlowPts(std::vector< wxPoint2DDouble > edges)
Calculate the points of the power flow arrows.
virtual void DrawDCPowerFlowPts(GUIColour *guiColour, wxGraphicsContext *gc) const
Draw power flow arrows.
virtual void DrawDCSwitches(GUIColour *guiColour, wxGraphicsContext *gc) const
Draw switch.
virtual wxPoint2DDouble GetSwitchPoint(Element *parent, wxPoint2DDouble parentPoint, wxPoint2DDouble secondPoint) const
Get the correct switch position.
std::vector< double > swTime