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);
46 wxPoint2DDouble parentPt =
50 m_pointList.push_back(parentPt);
51 m_pointList.push_back(
GetSwitchPoint(parent, parentPt, m_position));
53 wxRect2DDouble genRect(0, 0, 0, 0);
54 m_switchRect.push_back(genRect);
59 else if (parent != m_parentList[0]) {
60 m_parentList.push_back(parent);
62 wxPoint2DDouble parentPt =
69 wxPoint2DDouble((m_pointList[0].m_x + parentPt.m_x) / 2.0, (m_pointList[0].m_y + parentPt.m_y) / 2.0);
75 m_pointList.push_back(
76 wxPoint2DDouble(m_rect.GetPosition() + wxPoint2DDouble(-10 - m_borderSize, m_height / 2.0)));
77 m_pointList.push_back(
78 wxPoint2DDouble(m_rect.GetPosition() + wxPoint2DDouble(m_width + 10 + m_borderSize, m_height / 2.0)));
81 wxPoint2DDouble secondPoint = parentPt;
82 if (m_pointList.size() > 2) { secondPoint = m_pointList[2]; }
83 m_pointList[1] =
GetSwitchPoint(m_parentList[0], m_pointList[0], secondPoint);
86 m_pointList.push_back(
GetSwitchPoint(parent, parentPt, m_pointList[m_pointList.size() - 1]));
88 m_pointList.push_back(parentPt);
91 wxRect2DDouble genRect(0, 0, 0, 0);
92 m_switchRect.push_back(genRect);
94 UpdatePowerFlowArrowsPosition();
105 return m_rect.Contains(ptR);
188 wxColour elementColour;
191 elementColour = guiColour->eventElement;
193 elementColour = guiColour->enabled;
196 elementColour = guiColour->disable;
201 gc->SetPen(wxPen(guiColour->selection, 2 + m_borderSize * 2.0));
202 gc->SetBrush(*wxTRANSPARENT_BRUSH);
203 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
208 gc->Translate(m_position.m_x, m_position.m_y);
209 gc->Rotate(wxDegToRad(m_angle));
210 gc->Translate(-m_position.m_x, -m_position.m_y);
212 gc->SetPen(*wxTRANSPARENT_PEN);
213 gc->SetBrush(wxBrush(guiColour->selection));
214 DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20 + (m_borderSize + 1.5) / scale, 20, gc);
215 DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20 + (m_borderSize + 1.5) / scale, 20, gc);
220 gc->SetPen(*wxTRANSPARENT_PEN);
221 gc->SetBrush(wxBrush(guiColour->selection));
222 if (m_pointList.size() > 0) {
223 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc);
224 if (m_inserted) {
DrawDCCircle(m_pointList[m_pointList.size() - 1], 5.0 + m_borderSize / scale, 10, gc); }
230 gc->SetPen(wxPen(elementColour, 2));
231 gc->SetBrush(*wxTRANSPARENT_BRUSH);
232 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
235 gc->SetPen(*wxTRANSPARENT_PEN);
236 gc->SetBrush(wxBrush(elementColour));
237 if (m_pointList.size() > 0) {
239 if (m_inserted) {
DrawDCCircle(m_pointList[m_pointList.size() - 1], 5.0, 10, gc); }
248 gc->Translate(m_position.m_x, m_position.m_y);
249 gc->Rotate(wxDegToRad(m_angle));
250 gc->Translate(-m_position.m_x, -m_position.m_y);
253 gc->SetPen(*wxTRANSPARENT_PEN);
254 gc->SetBrush(wxBrush(guiColour->background));
255 DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20, 20, gc);
256 DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20, 20, gc);
258 gc->SetPen(wxPen(elementColour, 2));
259 gc->SetBrush(*wxTRANSPARENT_BRUSH);
260 DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20, 20, gc);
261 DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20, 20, gc);
264 gc->SetPen(*wxTRANSPARENT_PEN);
265 gc->SetBrush(wxBrush(elementColour));
274 wxColour elementColour;
277 elementColour = guiColour->eventElement;
279 elementColour = guiColour->enabled;
282 elementColour = guiColour->disable;
284 std::vector<wxPoint> pointList;
285 for (
auto& pt : m_pointList) { pointList.emplace_back(
static_cast<int>(pt.m_x),
static_cast<int>(pt.m_y)); }
290 dc.SetPen(wxPen(wxColour(guiColour->selection), 2 + m_borderSize * 2.0));
291 dc.SetBrush(*wxTRANSPARENT_BRUSH);
292 dc.DrawLines(pointList.size(), &pointList[0]);
294 dc.SetPen(*wxTRANSPARENT_PEN);
295 dc.SetBrush(wxBrush(guiColour->selection));
298 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(15.0, 0.0), m_angle), 20 + (m_borderSize + 1.5) / scale, dc);
299 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(-15.0, 0.0), m_angle), 20 + (m_borderSize + 1.5) / scale, dc);
302 dc.SetPen(*wxTRANSPARENT_PEN);
303 dc.SetBrush(wxBrush(guiColour->selection));
304 if (pointList.size() > 0) {
305 DrawDCCircle(pointList[0], 5.0 + m_borderSize / scale, dc);
306 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0 + m_borderSize / scale, dc); }
312 dc.SetPen(wxPen(elementColour, 2));
313 dc.SetBrush(*wxTRANSPARENT_BRUSH);
314 dc.DrawLines(pointList.size(), &pointList[0]);
317 dc.SetPen(*wxTRANSPARENT_PEN);
318 dc.SetBrush(wxBrush(elementColour));
319 if (pointList.size() > 0) {
321 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0, dc); }
327 dc.SetPen(*wxTRANSPARENT_PEN);
328 dc.SetBrush(wxBrush(guiColour->background));
329 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(15.0, 0.0), m_angle), 20, dc);
330 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(-15.0, 0.0), m_angle), 20, dc);
332 dc.SetPen(wxPen(elementColour, 2));
333 dc.SetBrush(*wxTRANSPARENT_BRUSH);
334 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(15.0, 0.0), m_angle), 20, dc);
335 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(-15.0, 0.0), m_angle), 20, dc);
338 dc.SetPen(*wxTRANSPARENT_PEN);
339 dc.SetBrush(wxBrush(elementColour));
340 DrawDCCircle(m_position + RotateLocal(wxPoint2DDouble(-35, -20), m_angle), 4, dc);
346 if (m_angle == 0.0 || m_angle == 180.0)
return m_rect.Intersects(rect);
352 double rotAngle = m_rotationAngle;
353 if (!clockwise) rotAngle = -m_rotationAngle;
356 if (m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
359 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) {
362 UpdateSwitchesPosition();
363 UpdatePowerFlowArrowsPosition();
371 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) { m_pointList[i] = m_movePts[i] + position - m_moveStartPt; }
373 if (!m_parentList[0]) { m_pointList[0] = m_movePts[0] + position - m_moveStartPt; }
374 if (!m_parentList[1]) {
375 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
378 UpdateSwitchesPosition();
379 UpdatePowerFlowArrowsPosition();
386 if (parent == m_parentList[0]) {
387 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
390 else if (parent == m_parentList[1]) {
391 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
395 if (m_activeNodeID == 1) {
396 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
397 if (m_parentList[0]) {
398 m_parentList[0]->RemoveChild(
this);
399 m_parentList[0] =
nullptr;
403 else if (m_activeNodeID == 2) {
404 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
405 if (m_parentList[1]) {
406 m_parentList[1]->RemoveChild(
this);
407 m_parentList[1] =
nullptr;
414 UpdateSwitchesPosition();
415 UpdatePowerFlowArrowsPosition();
420 m_moveStartPt = position;
421 m_movePts = m_pointList;
422 m_movePos = m_position;
429 wxString busName[2] = {
"?",
"?" };
430 if (m_parentList.size() == 2) {
432 for (
Element* element : m_parentList) {
434 Bus* bus =
static_cast<Bus*
>(element);
435 busName[i] = bus->GetElectricalData().name;
441 wxMenu* textMenu =
new wxMenu();
443 textMenu->Append(ID_TXT_NAME, _(
"Name"));
444 textMenu->Append(ID_TXT_BRANCH_ACTIVE_POWER_1_2, _(
"Active power (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
445 textMenu->Append(ID_TXT_BRANCH_ACTIVE_POWER_2_1, _(
"Active power (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
446 textMenu->Append(ID_TXT_BRANCH_REACTIVE_POWER_1_2, _(
"Reactive power (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
447 textMenu->Append(ID_TXT_BRANCH_REACTIVE_POWER_2_1, _(
"Reactive power (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
448 textMenu->Append(ID_TXT_BRANCH_LOSSES, _(
"Losses"));
449 textMenu->Append(ID_TXT_BRANCH_CURRENT_1_2, _(
"Current (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
450 textMenu->Append(ID_TXT_BRANCH_CURRENT_2_1, _(
"Current (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
451 textMenu->Append(ID_TXT_BRANCH_FAULT_CURRENT_1_2, _(
"Fault current (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
452 textMenu->Append(ID_TXT_BRANCH_FAULT_CURRENT_2_1, _(
"Fault current (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
453 textMenu->SetClientData(menu.GetClientData());
454 menu.AppendSubMenu(textMenu, _(
"Add text"));
463 transfForm.CenterOnParent();
464 if (transfForm.ShowModal() == wxID_OK) {
472 if (nominalVoltage.size() == 1) {
473 m_electricalData.primaryNominalVoltage = nominalVoltage[0];
474 m_electricalData.primaryNominalVoltageUnit = nominalVoltageUnit[0];
476 else if (nominalVoltage.size() == 2) {
477 m_electricalData.primaryNominalVoltage = nominalVoltage[0];
478 m_electricalData.primaryNominalVoltageUnit = nominalVoltageUnit[0];
479 m_electricalData.secondaryNominalVoltage = nominalVoltage[1];
480 m_electricalData.secondaryNominalVoltageUnit = nominalVoltageUnit[1];
484void Transformer::UpdatePowerFlowArrowsPosition()
486 std::vector<wxPoint2DDouble> edges;
487 switch (m_pfDirection) {
489 m_powerFlowArrow.clear();
492 for (
int i = 1; i < (int)m_pointList.size() - 1; i++) { edges.push_back(m_pointList[i]); }
495 for (
int i = (
int)m_pointList.size() - 2; i > 0; i--) { edges.push_back(m_pointList[i]); }
505 double rotAngle = m_rotationAngle;
506 if (!clockwise) rotAngle = -m_rotationAngle;
508 if (parent == m_parentList[0]) {
511 else if (parent == m_parentList[1]) {
512 m_pointList[m_pointList.size() - 1] = parent->
RotateAtPosition(m_pointList[m_pointList.size() - 1], rotAngle);
514 UpdateSwitchesPosition();
515 UpdatePowerFlowArrowsPosition();
520 if (m_activeNodeID == 1 && parent == m_parentList[0])
return false;
521 if (m_activeNodeID == 2 && parent == m_parentList[1])
return false;
523 if (parent && m_activeNodeID != 0) {
524 wxRect2DDouble nodeRect(0, 0, 0, 0);
525 if (m_activeNodeID == 1) {
526 nodeRect = wxRect2DDouble(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
527 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
529 if (m_activeNodeID == 2) {
530 nodeRect = wxRect2DDouble(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
531 m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize,
532 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
536 if (m_activeNodeID == 1) {
538 if (m_parentList[1] == parent) {
543 m_parentList[0] = parent;
547 m_pointList[0], -parent->
GetAngle());
550 m_pointList[0] = parentPt;
552 UpdateSwitchesPosition();
553 UpdatePowerFlowArrowsPosition();
556 if (m_activeNodeID == 2) {
557 if (m_parentList[0] == parent) {
562 m_parentList[1] = parent;
564 wxPoint2DDouble parentPt =
568 m_pointList[m_pointList.size() - 1] = parentPt;
570 UpdateSwitchesPosition();
571 UpdatePowerFlowArrowsPosition();
576 if (m_activeNodeID == 1) m_parentList[0] =
nullptr;
577 if (m_activeNodeID == 2) m_parentList[1] =
nullptr;
585 m_pfDirection = pfDirection;
586 UpdatePowerFlowArrowsPosition();
598 wxString tipText = m_electricalData.name;
599 wxString primVoltage =
StringFromDouble(m_electricalData.primaryNominalVoltage);
600 switch (m_electricalData.primaryNominalVoltageUnit) {
601 case ElectricalUnit::UNIT_V: {
602 primVoltage += _(
" V");
604 case ElectricalUnit::UNIT_kV: {
605 primVoltage += _(
" kV");
610 wxString secVoltage =
StringFromDouble(m_electricalData.secondaryNominalVoltage);
611 switch (m_electricalData.secondaryNominalVoltageUnit) {
612 case ElectricalUnit::UNIT_V: {
613 secVoltage += _(
" V");
615 case ElectricalUnit::UNIT_kV: {
616 secVoltage += _(
" kV");
622 tipText +=
"\n" + primVoltage +
" / " + secVoltage;
627 busNumber[0] =
static_cast<Bus*
>(m_parentList[0])->GetElectricalData().number + 1;
628 busNumber[1] =
static_cast<Bus*
>(m_parentList[1])->GetElectricalData().number + 1;
630 tipText += _(
"\nP") + wxString::Format(
"(%d-%d) = ", busNumber[0], busNumber[1]) +
631 wxString::FromDouble(m_electricalData.powerFlow[0].real(), 5) + _(
" p.u.");
632 tipText += _(
"\nQ") + wxString::Format(
"(%d-%d) = ", busNumber[0], busNumber[1]) +
633 wxString::FromDouble(m_electricalData.powerFlow[0].imag(), 5) + _(
" p.u.");
634 tipText += _(
"\nP") + wxString::Format(
"(%d-%d) = ", busNumber[1], busNumber[0]) +
635 wxString::FromDouble(m_electricalData.powerFlow[1].real(), 5) + _(
" p.u.");
636 tipText += _(
"\nQ") + wxString::Format(
"(%d-%d) = ", busNumber[1], busNumber[0]) +
637 wxString::FromDouble(m_electricalData.powerFlow[1].imag(), 5) + _(
" p.u.");
639 if (!m_electricalData.harmonicOrder.empty()) {
640 tipText += _(
"\n\nHarmonic currents:");
642 for (
auto& hCurrent1 : m_electricalData.harmonicCurrent[0]) {
643 auto& hCurrent2 = m_electricalData.harmonicCurrent[1][i];
645 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'));
646 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'));
661 data.name = m_electricalData.name;
663 data.nominalPower = m_electricalData.nominalPower;
664 data.nominalPowerUnit = m_electricalData.nominalPowerUnit;
666 data.primaryNominalVoltage = m_electricalData.primaryNominalVoltage;
667 data.primaryNominalVoltageUnit = m_electricalData.primaryNominalVoltageUnit;
669 data.secondaryNominalVoltage = m_electricalData.secondaryNominalVoltage;
670 data.secondaryNominalVoltageUnit = m_electricalData.secondaryNominalVoltageUnit;
672 data.useTransformerPower = m_electricalData.useTransformerPower;
674 data.baseVoltage = m_electricalData.baseVoltage;
676 data.resistance = m_electricalData.resistance;
677 data.resistanceUnit = m_electricalData.resistanceUnit;
679 data.indReactance = m_electricalData.indReactance;
680 data.indReactanceUnit = m_electricalData.indReactanceUnit;
682 data.connection = m_electricalData.connection;
683 data.turnsRatio = m_electricalData.turnsRatio;
684 data.phaseShift = m_electricalData.phaseShift;
686 data.zeroResistance = m_electricalData.zeroResistance;
687 data.zeroIndReactance = m_electricalData.zeroIndReactance;
689 data.primaryGrndResistance = m_electricalData.primaryGrndResistance;
690 data.primaryGrndReactance = m_electricalData.primaryGrndReactance;
692 data.secondaryGrndResistance = m_electricalData.secondaryGrndResistance;
693 data.secondaryGrndReactance = m_electricalData.secondaryGrndReactance;
695 data.powerFlow[0] = m_electricalData.powerFlow[0];
696 data.powerFlow[1] = m_electricalData.powerFlow[1];
698 data.harmonicOrder = m_electricalData.harmonicOrder;
699 data.harmonicCurrent[0] = m_electricalData.harmonicCurrent[0];
700 data.harmonicCurrent[1] = m_electricalData.harmonicCurrent[1];
702 double transformerBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
703 double baseVoltage = 0.0;
704 if (data.baseVoltage == 0) {
705 baseVoltage = GetValueFromUnit(data.primaryNominalVoltage, data.primaryNominalVoltageUnit);
708 baseVoltage = GetValueFromUnit(data.secondaryNominalVoltage, data.secondaryNominalVoltageUnit);
710 double systemBaseImpedance = (baseVoltage * baseVoltage) / systemBasePower;
711 double transformerBaseImpedance = (baseVoltage * baseVoltage) / transformerBasePower;
714 double r = data.resistance;
715 if (data.resistanceUnit == ElectricalUnit::UNIT_PU) {
716 if (data.useTransformerPower) data.resistance = (r * transformerBaseImpedance) / systemBaseImpedance;
719 data.resistance = r / systemBaseImpedance;
721 data.resistanceUnit = ElectricalUnit::UNIT_PU;
724 double x = data.indReactance;
725 if (data.indReactanceUnit == ElectricalUnit::UNIT_PU) {
726 if (data.useTransformerPower) data.indReactance = (x * transformerBaseImpedance) / systemBaseImpedance;
729 data.indReactance = x / systemBaseImpedance;
731 data.indReactanceUnit = ElectricalUnit::UNIT_PU;
736 double r0 = data.zeroResistance;
737 if (data.useTransformerPower) data.zeroResistance = (r0 * transformerBaseImpedance) / systemBaseImpedance;
740 double x0 = data.zeroIndReactance;
741 if (data.useTransformerPower) data.zeroIndReactance = (x0 * transformerBaseImpedance) / systemBaseImpedance;
744 double rgp = data.primaryGrndResistance;
745 if (data.useTransformerPower) data.primaryGrndResistance = (rgp * transformerBaseImpedance) / systemBaseImpedance;
748 double xgp = data.primaryGrndReactance;
749 if (data.useTransformerPower) data.primaryGrndReactance = (xgp * transformerBaseImpedance) / systemBaseImpedance;
752 double rgs = data.secondaryGrndResistance;
753 if (data.useTransformerPower) data.secondaryGrndResistance = (rgs * transformerBaseImpedance) / systemBaseImpedance;
756 double xgs = data.secondaryGrndReactance;
757 if (data.useTransformerPower) data.secondaryGrndReactance = (xgs * transformerBaseImpedance) / systemBaseImpedance;
760 data.powerFlow[0] = std::complex<double>(0, 0);
761 data.powerFlow[1] = std::complex<double>(0, 0);
762 data.faultCurrent[0][0] = std::complex<double>(0, 0);
763 data.faultCurrent[0][1] = std::complex<double>(0, 0);
764 data.faultCurrent[0][2] = std::complex<double>(0, 0);
765 data.faultCurrent[1][0] = std::complex<double>(0, 0);
766 data.faultCurrent[1][1] = std::complex<double>(0, 0);
767 data.faultCurrent[1][2] = std::complex<double>(0, 0);
773rapidxml::xml_node<>* Transformer::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
775 auto elementNode = XMLParser::AppendNode(doc, elementListNode,
"Transfomer");
776 XMLParser::SetNodeAttribute(doc, elementNode,
"ID", m_elementID);
777 auto cadProp = XMLParser::AppendNode(doc, elementNode,
"CADProperties");
778 auto position = XMLParser::AppendNode(doc, cadProp,
"Position");
779 auto posX = XMLParser::AppendNode(doc, position,
"X");
780 XMLParser::SetNodeValue(doc, posX, m_position.m_x);
781 auto posY = XMLParser::AppendNode(doc, position,
"Y");
782 XMLParser::SetNodeValue(doc, posY, m_position.m_y);
783 auto size = XMLParser::AppendNode(doc, cadProp,
"Size");
784 auto width = XMLParser::AppendNode(doc, size,
"Width");
785 XMLParser::SetNodeValue(doc, width, m_width);
786 auto height = XMLParser::AppendNode(doc, size,
"Height");
787 XMLParser::SetNodeValue(doc, height, m_height);
788 auto angle = XMLParser::AppendNode(doc, cadProp,
"Angle");
789 XMLParser::SetNodeValue(doc, angle, m_angle);
790 auto nodeList = XMLParser::AppendNode(doc, cadProp,
"NodeList");
791 auto nodePos1 = XMLParser::AppendNode(doc, nodeList,
"Node");
792 XMLParser::SetNodeAttribute(doc, nodePos1,
"ID", 0);
793 auto nodePosX1 = XMLParser::AppendNode(doc, nodePos1,
"X");
794 XMLParser::SetNodeValue(doc, nodePosX1, m_pointList[0].m_x);
795 auto nodePosY1 = XMLParser::AppendNode(doc, nodePos1,
"Y");
796 XMLParser::SetNodeValue(doc, nodePosY1, m_pointList[0].m_y);
797 auto nodePos2 = XMLParser::AppendNode(doc, nodeList,
"Node");
798 XMLParser::SetNodeAttribute(doc, nodePos2,
"ID", 1);
799 auto nodePosX2 = XMLParser::AppendNode(doc, nodePos2,
"X");
800 XMLParser::SetNodeValue(doc, nodePosX2, m_pointList[m_pointList.size() - 1].m_x);
801 auto nodePosY2 = XMLParser::AppendNode(doc, nodePos2,
"Y");
802 XMLParser::SetNodeValue(doc, nodePosY2, m_pointList[m_pointList.size() - 1].m_y);
804 auto parentIDList = XMLParser::AppendNode(doc, cadProp,
"ParentIDList");
805 for (
unsigned int i = 0; i < m_parentList.size(); i++) {
806 Element* parent = m_parentList[i];
808 auto parentID = XMLParser::AppendNode(doc, parentIDList,
"ParentID");
809 XMLParser::SetNodeAttribute(doc, parentID,
"ID",
static_cast<int>(i));
810 XMLParser::SetNodeValue(doc, parentID, parent->
GetID());
814 auto electricalProp = XMLParser::AppendNode(doc, elementNode,
"ElectricalProperties");
815 auto isOnline = XMLParser::AppendNode(doc, electricalProp,
"IsOnline");
816 XMLParser::SetNodeValue(doc, isOnline, m_online);
817 auto name = XMLParser::AppendNode(doc, electricalProp,
"Name");
818 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
819 auto primaryNominalVoltage = XMLParser::AppendNode(doc, electricalProp,
"PrimaryNominalVoltage");
820 XMLParser::SetNodeValue(doc, primaryNominalVoltage, m_electricalData.primaryNominalVoltage);
821 XMLParser::SetNodeAttribute(doc, primaryNominalVoltage,
"UnitID",
static_cast<int>(m_electricalData.primaryNominalVoltageUnit));
822 auto secondaryNominalVoltage = XMLParser::AppendNode(doc, electricalProp,
"SecondaryNominalVoltage");
823 XMLParser::SetNodeValue(doc, secondaryNominalVoltage, m_electricalData.secondaryNominalVoltage);
824 XMLParser::SetNodeAttribute(doc, secondaryNominalVoltage,
"UnitID",
static_cast<int>(m_electricalData.secondaryNominalVoltageUnit));
825 auto nominalPower = XMLParser::AppendNode(doc, electricalProp,
"NominalPower");
826 XMLParser::SetNodeValue(doc, nominalPower, m_electricalData.nominalPower);
827 XMLParser::SetNodeAttribute(doc, nominalPower,
"UnitID",
static_cast<int>(m_electricalData.nominalPowerUnit));
828 auto resistance = XMLParser::AppendNode(doc, electricalProp,
"Resistance");
829 XMLParser::SetNodeValue(doc, resistance, m_electricalData.resistance);
830 XMLParser::SetNodeAttribute(doc, resistance,
"UnitID",
static_cast<int>(m_electricalData.resistanceUnit));
831 auto indReactance = XMLParser::AppendNode(doc, electricalProp,
"IndReactance");
832 XMLParser::SetNodeValue(doc, indReactance, m_electricalData.indReactance);
833 XMLParser::SetNodeAttribute(doc, indReactance,
"UnitID",
static_cast<int>(m_electricalData.indReactanceUnit));
834 auto connection = XMLParser::AppendNode(doc, electricalProp,
"Connection");
835 XMLParser::SetNodeValue(doc, connection, m_electricalData.connection);
836 auto turnsRatio = XMLParser::AppendNode(doc, electricalProp,
"TurnsRatio");
837 XMLParser::SetNodeValue(doc, turnsRatio, m_electricalData.turnsRatio);
838 auto phaseShift = XMLParser::AppendNode(doc, electricalProp,
"PhaseShift");
839 XMLParser::SetNodeValue(doc, phaseShift, m_electricalData.phaseShift);
840 auto useTransformerPower = XMLParser::AppendNode(doc, electricalProp,
"UseTransfomerPower");
841 XMLParser::SetNodeValue(doc, useTransformerPower, m_electricalData.useTransformerPower);
843 auto fault = XMLParser::AppendNode(doc, electricalProp,
"Fault");
844 auto zeroResistance = XMLParser::AppendNode(doc, fault,
"ZeroResistance");
845 XMLParser::SetNodeValue(doc, zeroResistance, m_electricalData.zeroResistance);
846 auto zeroIndReactance = XMLParser::AppendNode(doc, fault,
"ZeroIndReactance");
847 XMLParser::SetNodeValue(doc, zeroIndReactance, m_electricalData.zeroIndReactance);
848 auto primaryGrndResistance = XMLParser::AppendNode(doc, fault,
"PrimaryGrndResistance");
849 XMLParser::SetNodeValue(doc, primaryGrndResistance, m_electricalData.primaryGrndResistance);
850 auto primaryGrndReactance = XMLParser::AppendNode(doc, fault,
"PrimaryGrndReactance");
851 XMLParser::SetNodeValue(doc, primaryGrndReactance, m_electricalData.primaryGrndReactance);
852 auto secondaryGrndResistance = XMLParser::AppendNode(doc, fault,
"SecondaryGrndResistance");
853 XMLParser::SetNodeValue(doc, secondaryGrndResistance, m_electricalData.secondaryGrndResistance);
854 auto secondaryGrndReactance = XMLParser::AppendNode(doc, fault,
"SecondaryGrndReactance");
855 XMLParser::SetNodeValue(doc, secondaryGrndReactance, m_electricalData.secondaryGrndReactance);
857 SaveSwitchingData(doc, electricalProp);
862bool Transformer::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
864 auto cadPropNode = elementNode->first_node(
"CADProperties");
865 if (!cadPropNode)
return false;
867 auto position = cadPropNode->first_node(
"Position");
868 double posX = XMLParser::GetNodeValueDouble(position,
"X");
869 double posY = XMLParser::GetNodeValueDouble(position,
"Y");
870 auto size = cadPropNode->first_node(
"Size");
871 m_width = XMLParser::GetNodeValueDouble(size,
"Width");
872 m_height = XMLParser::GetNodeValueDouble(size,
"Height");
873 double angle = XMLParser::GetNodeValueDouble(cadPropNode,
"Angle");
876 std::vector<wxPoint2DDouble> ptsList;
877 auto nodePosList = cadPropNode->first_node(
"NodeList");
878 if (!nodePosList)
return false;
879 auto nodePos = nodePosList->first_node(
"Node");
881 double nodePosX = XMLParser::GetNodeValueDouble(nodePos,
"X");
882 double nodePosY = XMLParser::GetNodeValueDouble(nodePos,
"Y");
883 ptsList.push_back(wxPoint2DDouble(nodePosX, nodePosY));
884 nodePos = nodePos->next_sibling(
"Node");
888 auto parentIDList = cadPropNode->first_node(
"ParentIDList");
889 if (!parentIDList)
return false;
890 auto parentNode = parentIDList->first_node(
"ParentID");
891 long parentID[2] = { -1, -1 };
894 wxString(parentNode->first_attribute(
"ID")->value()).ToLong(&index);
895 wxString(parentNode->value()).ToCLong(&parentID[index]);
896 parentNode = parentNode->next_sibling(
"ParentID");
899 std::vector<wxPoint2DDouble> nodePtsList;
900 nodePtsList.push_back(ptsList[0]);
901 nodePtsList.push_back(ptsList[ptsList.size() - 1]);
904 std::vector<Bus*> dummyBusList;
906 for (
unsigned int i = 0; i < 2; ++i) {
907 if (parentID[i] == -1)
909 Bus* dummyBus =
new Bus(nodePtsList[i]);
910 dummyBusList.push_back(dummyBus);
914 AddParent(parentList[parentID[i]], nodePtsList[i]);
919 Move(wxPoint2DDouble(posX, posY));
922 for (
auto it = dummyBusList.begin(), itEnd = dummyBusList.end(); it != itEnd; ++it) {
926 dummyBusList.clear();
930 bool clockwise =
true;
932 numRot = std::abs(numRot);
935 for (
int i = 0; i < numRot; i++)
Rotate(clockwise);
937 auto electricalProp = elementNode->first_node(
"ElectricalProperties");
938 if (!electricalProp)
return false;
940 SetOnline(XMLParser::GetNodeValueInt(electricalProp,
"IsOnline"));
941 m_electricalData.name = electricalProp->first_node(
"Name")->value();
942 m_electricalData.primaryNominalVoltage = XMLParser::GetNodeValueDouble(electricalProp,
"PrimaryNominalVoltage");
943 m_electricalData.primaryNominalVoltageUnit =
944 static_cast<ElectricalUnit
>(XMLParser::GetAttributeValueInt(electricalProp,
"PrimaryNominalVoltage",
"UnitID"));
945 m_electricalData.secondaryNominalVoltage = XMLParser::GetNodeValueDouble(electricalProp,
"SecondaryNominalVoltage");
946 m_electricalData.secondaryNominalVoltageUnit =
static_cast<ElectricalUnit
>(
947 XMLParser::GetAttributeValueInt(electricalProp,
"SecondaryNominalVoltage",
"UnitID"));
948 m_electricalData.nominalPower = XMLParser::GetNodeValueDouble(electricalProp,
"NominalPower");
949 m_electricalData.nominalPowerUnit =
950 static_cast<ElectricalUnit
>(XMLParser::GetAttributeValueInt(electricalProp,
"NominalPower",
"UnitID"));
951 m_electricalData.resistance = XMLParser::GetNodeValueDouble(electricalProp,
"Resistance");
952 m_electricalData.resistanceUnit =
953 static_cast<ElectricalUnit
>(XMLParser::GetAttributeValueInt(electricalProp,
"Resistance",
"UnitID"));
954 m_electricalData.indReactance = XMLParser::GetNodeValueDouble(electricalProp,
"IndReactance");
955 m_electricalData.indReactanceUnit =
956 static_cast<ElectricalUnit
>(XMLParser::GetAttributeValueInt(electricalProp,
"IndReactance",
"UnitID"));
957 m_electricalData.connection = (TransformerConnection)XMLParser::GetNodeValueInt(electricalProp,
"Connection");
958 m_electricalData.turnsRatio = XMLParser::GetNodeValueDouble(electricalProp,
"TurnsRatio");
959 m_electricalData.phaseShift = XMLParser::GetNodeValueDouble(electricalProp,
"PhaseShift");
960 m_electricalData.useTransformerPower = XMLParser::GetNodeValueInt(electricalProp,
"UseTransfomerPower");
962 auto fault = electricalProp->first_node(
"Fault");
963 m_electricalData.zeroResistance = XMLParser::GetNodeValueDouble(fault,
"ZeroResistance");
964 m_electricalData.zeroIndReactance = XMLParser::GetNodeValueDouble(fault,
"ZeroIndReactance");
965 m_electricalData.primaryGrndResistance = XMLParser::GetNodeValueDouble(fault,
"PrimaryGrndResistance");
966 m_electricalData.primaryGrndReactance = XMLParser::GetNodeValueDouble(fault,
"PrimaryGrndReactance");
967 m_electricalData.secondaryGrndResistance = XMLParser::GetNodeValueDouble(fault,
"SecondaryGrndResistance");
968 m_electricalData.secondaryGrndReactance = XMLParser::GetNodeValueDouble(fault,
"SecondaryGrndReactance");
970 if (!OpenSwitchingData(electricalProp))
return false;
976void Transformer::SetBestPositionAndRotation()
978 wxPoint2DDouble p1 = m_pointList[0];
979 wxPoint2DDouble p2 = m_pointList[m_pointList.size() - 1];
980 wxPoint2DDouble mid = (p1 + p2) / 2.0;
983 double bestAngle = wxRadToDeg(std::atan2(p2.m_y - p1.m_y, p2.m_x - p1.m_x));
984 bool clockwise = bestAngle > 0 ? true :
false;
985 while (std::abs(m_angle) < std::abs(bestAngle)) {
Rotate(clockwise); }
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.
virtual void GeneralMenuItens(wxMenu &menu)
Insert general itens to context menu.
double GetRotationAngle() const
Get the angle of rotation.
wxPoint2DDouble GetPosition() const
Get the element position.
double GetAngle() const
Get the element angle.
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