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 = m_dynamicEventColour;
193 elementColour = m_onlineElementColour;
196 elementColour = m_offlineElementColour;
201 gc->SetPen(wxPen(wxColour(m_selectionColour), 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(m_selectionColour));
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(m_selectionColour));
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(*wxWHITE_BRUSH);
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 = m_dynamicEventColour;
279 elementColour = m_onlineElementColour;
282 elementColour = m_offlineElementColour;
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(m_selectionColour), 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(m_selectionColour));
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(m_selectionColour));
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(*wxWHITE_BRUSH);
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) {
602 primVoltage += _(
" V");
605 primVoltage += _(
" kV");
610 wxString secVoltage =
StringFromDouble(m_electricalData.secondaryNominalVoltage);
611 switch (m_electricalData.secondaryNominalVoltageUnit) {
613 secVoltage += _(
" V");
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'));
660 double transformerBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
661 double baseVoltage = 0.0;
662 if (data.baseVoltage == 0) {
663 baseVoltage = GetValueFromUnit(data.primaryNominalVoltage, data.primaryNominalVoltageUnit);
666 baseVoltage = GetValueFromUnit(data.secondaryNominalVoltage, data.secondaryNominalVoltageUnit);
668 double systemBaseImpedance = (baseVoltage * baseVoltage) / systemBasePower;
669 double transformerBaseImpedance = (baseVoltage * baseVoltage) / transformerBasePower;
672 double r = data.resistance;
674 if (data.useTransformerPower) data.resistance = (r * transformerBaseImpedance) / systemBaseImpedance;
677 data.resistance = r / systemBaseImpedance;
682 double x = data.indReactance;
684 if (data.useTransformerPower) data.indReactance = (x * transformerBaseImpedance) / systemBaseImpedance;
687 data.indReactance = x / systemBaseImpedance;
694 double r0 = data.zeroResistance;
695 if (data.useTransformerPower) data.zeroResistance = (r0 * transformerBaseImpedance) / systemBaseImpedance;
698 double x0 = data.zeroIndReactance;
699 if (data.useTransformerPower) data.zeroIndReactance = (x0 * transformerBaseImpedance) / systemBaseImpedance;
702 double rgp = data.primaryGrndResistance;
703 if (data.useTransformerPower) data.primaryGrndResistance = (rgp * transformerBaseImpedance) / systemBaseImpedance;
706 double xgp = data.primaryGrndReactance;
707 if (data.useTransformerPower) data.primaryGrndReactance = (xgp * transformerBaseImpedance) / systemBaseImpedance;
710 double rgs = data.secondaryGrndResistance;
711 if (data.useTransformerPower) data.secondaryGrndResistance = (rgs * transformerBaseImpedance) / systemBaseImpedance;
714 double xgs = data.secondaryGrndReactance;
715 if (data.useTransformerPower) data.secondaryGrndReactance = (xgs * transformerBaseImpedance) / systemBaseImpedance;
718 data.powerFlow[0] = std::complex<double>(0, 0);
719 data.powerFlow[1] = std::complex<double>(0, 0);
720 data.faultCurrent[0][0] = std::complex<double>(0, 0);
721 data.faultCurrent[0][1] = std::complex<double>(0, 0);
722 data.faultCurrent[0][2] = std::complex<double>(0, 0);
723 data.faultCurrent[1][0] = std::complex<double>(0, 0);
724 data.faultCurrent[1][1] = std::complex<double>(0, 0);
725 data.faultCurrent[1][2] = std::complex<double>(0, 0);
731rapidxml::xml_node<>* Transformer::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
733 auto elementNode = XMLParser::AppendNode(doc, elementListNode,
"Transfomer");
734 XMLParser::SetNodeAttribute(doc, elementNode,
"ID", m_elementID);
735 auto cadProp = XMLParser::AppendNode(doc, elementNode,
"CADProperties");
736 auto position = XMLParser::AppendNode(doc, cadProp,
"Position");
737 auto posX = XMLParser::AppendNode(doc, position,
"X");
738 XMLParser::SetNodeValue(doc, posX, m_position.m_x);
739 auto posY = XMLParser::AppendNode(doc, position,
"Y");
740 XMLParser::SetNodeValue(doc, posY, m_position.m_y);
741 auto size = XMLParser::AppendNode(doc, cadProp,
"Size");
742 auto width = XMLParser::AppendNode(doc, size,
"Width");
743 XMLParser::SetNodeValue(doc, width, m_width);
744 auto height = XMLParser::AppendNode(doc, size,
"Height");
745 XMLParser::SetNodeValue(doc, height, m_height);
746 auto angle = XMLParser::AppendNode(doc, cadProp,
"Angle");
747 XMLParser::SetNodeValue(doc, angle, m_angle);
748 auto nodeList = XMLParser::AppendNode(doc, cadProp,
"NodeList");
749 auto nodePos1 = XMLParser::AppendNode(doc, nodeList,
"Node");
750 XMLParser::SetNodeAttribute(doc, nodePos1,
"ID", 0);
751 auto nodePosX1 = XMLParser::AppendNode(doc, nodePos1,
"X");
752 XMLParser::SetNodeValue(doc, nodePosX1, m_pointList[0].m_x);
753 auto nodePosY1 = XMLParser::AppendNode(doc, nodePos1,
"Y");
754 XMLParser::SetNodeValue(doc, nodePosY1, m_pointList[0].m_y);
755 auto nodePos2 = XMLParser::AppendNode(doc, nodeList,
"Node");
756 XMLParser::SetNodeAttribute(doc, nodePos2,
"ID", 1);
757 auto nodePosX2 = XMLParser::AppendNode(doc, nodePos2,
"X");
758 XMLParser::SetNodeValue(doc, nodePosX2, m_pointList[m_pointList.size() - 1].m_x);
759 auto nodePosY2 = XMLParser::AppendNode(doc, nodePos2,
"Y");
760 XMLParser::SetNodeValue(doc, nodePosY2, m_pointList[m_pointList.size() - 1].m_y);
762 auto parentIDList = XMLParser::AppendNode(doc, cadProp,
"ParentIDList");
763 for (
unsigned int i = 0; i < m_parentList.size(); i++) {
764 Element* parent = m_parentList[i];
766 auto parentID = XMLParser::AppendNode(doc, parentIDList,
"ParentID");
767 XMLParser::SetNodeAttribute(doc, parentID,
"ID",
static_cast<int>(i));
768 XMLParser::SetNodeValue(doc, parentID, parent->
GetID());
772 auto electricalProp = XMLParser::AppendNode(doc, elementNode,
"ElectricalProperties");
773 auto isOnline = XMLParser::AppendNode(doc, electricalProp,
"IsOnline");
774 XMLParser::SetNodeValue(doc, isOnline, m_online);
775 auto name = XMLParser::AppendNode(doc, electricalProp,
"Name");
776 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
777 auto primaryNominalVoltage = XMLParser::AppendNode(doc, electricalProp,
"PrimaryNominalVoltage");
778 XMLParser::SetNodeValue(doc, primaryNominalVoltage, m_electricalData.primaryNominalVoltage);
779 XMLParser::SetNodeAttribute(doc, primaryNominalVoltage,
"UnitID",
static_cast<int>(m_electricalData.primaryNominalVoltageUnit));
780 auto secondaryNominalVoltage = XMLParser::AppendNode(doc, electricalProp,
"SecondaryNominalVoltage");
781 XMLParser::SetNodeValue(doc, secondaryNominalVoltage, m_electricalData.secondaryNominalVoltage);
782 XMLParser::SetNodeAttribute(doc, secondaryNominalVoltage,
"UnitID",
static_cast<int>(m_electricalData.secondaryNominalVoltageUnit));
783 auto nominalPower = XMLParser::AppendNode(doc, electricalProp,
"NominalPower");
784 XMLParser::SetNodeValue(doc, nominalPower, m_electricalData.nominalPower);
785 XMLParser::SetNodeAttribute(doc, nominalPower,
"UnitID",
static_cast<int>(m_electricalData.nominalPowerUnit));
786 auto resistance = XMLParser::AppendNode(doc, electricalProp,
"Resistance");
787 XMLParser::SetNodeValue(doc, resistance, m_electricalData.resistance);
788 XMLParser::SetNodeAttribute(doc, resistance,
"UnitID",
static_cast<int>(m_electricalData.resistanceUnit));
789 auto indReactance = XMLParser::AppendNode(doc, electricalProp,
"IndReactance");
790 XMLParser::SetNodeValue(doc, indReactance, m_electricalData.indReactance);
791 XMLParser::SetNodeAttribute(doc, indReactance,
"UnitID",
static_cast<int>(m_electricalData.indReactanceUnit));
792 auto connection = XMLParser::AppendNode(doc, electricalProp,
"Connection");
793 XMLParser::SetNodeValue(doc, connection, m_electricalData.connection);
794 auto turnsRatio = XMLParser::AppendNode(doc, electricalProp,
"TurnsRatio");
795 XMLParser::SetNodeValue(doc, turnsRatio, m_electricalData.turnsRatio);
796 auto phaseShift = XMLParser::AppendNode(doc, electricalProp,
"PhaseShift");
797 XMLParser::SetNodeValue(doc, phaseShift, m_electricalData.phaseShift);
798 auto useTransformerPower = XMLParser::AppendNode(doc, electricalProp,
"UseTransfomerPower");
799 XMLParser::SetNodeValue(doc, useTransformerPower, m_electricalData.useTransformerPower);
801 auto fault = XMLParser::AppendNode(doc, electricalProp,
"Fault");
802 auto zeroResistance = XMLParser::AppendNode(doc, fault,
"ZeroResistance");
803 XMLParser::SetNodeValue(doc, zeroResistance, m_electricalData.zeroResistance);
804 auto zeroIndReactance = XMLParser::AppendNode(doc, fault,
"ZeroIndReactance");
805 XMLParser::SetNodeValue(doc, zeroIndReactance, m_electricalData.zeroIndReactance);
806 auto primaryGrndResistance = XMLParser::AppendNode(doc, fault,
"PrimaryGrndResistance");
807 XMLParser::SetNodeValue(doc, primaryGrndResistance, m_electricalData.primaryGrndResistance);
808 auto primaryGrndReactance = XMLParser::AppendNode(doc, fault,
"PrimaryGrndReactance");
809 XMLParser::SetNodeValue(doc, primaryGrndReactance, m_electricalData.primaryGrndReactance);
810 auto secondaryGrndResistance = XMLParser::AppendNode(doc, fault,
"SecondaryGrndResistance");
811 XMLParser::SetNodeValue(doc, secondaryGrndResistance, m_electricalData.secondaryGrndResistance);
812 auto secondaryGrndReactance = XMLParser::AppendNode(doc, fault,
"SecondaryGrndReactance");
813 XMLParser::SetNodeValue(doc, secondaryGrndReactance, m_electricalData.secondaryGrndReactance);
815 SaveSwitchingData(doc, electricalProp);
820bool Transformer::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
822 auto cadPropNode = elementNode->first_node(
"CADProperties");
823 if (!cadPropNode)
return false;
825 auto position = cadPropNode->first_node(
"Position");
826 double posX = XMLParser::GetNodeValueDouble(position,
"X");
827 double posY = XMLParser::GetNodeValueDouble(position,
"Y");
828 auto size = cadPropNode->first_node(
"Size");
829 m_width = XMLParser::GetNodeValueDouble(size,
"Width");
830 m_height = XMLParser::GetNodeValueDouble(size,
"Height");
831 double angle = XMLParser::GetNodeValueDouble(cadPropNode,
"Angle");
834 std::vector<wxPoint2DDouble> ptsList;
835 auto nodePosList = cadPropNode->first_node(
"NodeList");
836 if (!nodePosList)
return false;
837 auto nodePos = nodePosList->first_node(
"Node");
839 double nodePosX = XMLParser::GetNodeValueDouble(nodePos,
"X");
840 double nodePosY = XMLParser::GetNodeValueDouble(nodePos,
"Y");
841 ptsList.push_back(wxPoint2DDouble(nodePosX, nodePosY));
842 nodePos = nodePos->next_sibling(
"Node");
846 auto parentIDList = cadPropNode->first_node(
"ParentIDList");
847 if (!parentIDList)
return false;
848 auto parentNode = parentIDList->first_node(
"ParentID");
849 long parentID[2] = { -1, -1 };
852 wxString(parentNode->first_attribute(
"ID")->value()).ToLong(&index);
853 wxString(parentNode->value()).ToCLong(&parentID[index]);
854 parentNode = parentNode->next_sibling(
"ParentID");
857 std::vector<wxPoint2DDouble> nodePtsList;
858 nodePtsList.push_back(ptsList[0]);
859 nodePtsList.push_back(ptsList[ptsList.size() - 1]);
862 std::vector<Bus*> dummyBusList;
864 for (
unsigned int i = 0; i < 2; ++i) {
865 if (parentID[i] == -1)
867 Bus* dummyBus =
new Bus(nodePtsList[i]);
868 dummyBusList.push_back(dummyBus);
872 AddParent(parentList[parentID[i]], nodePtsList[i]);
877 Move(wxPoint2DDouble(posX, posY));
880 for (
auto it = dummyBusList.begin(), itEnd = dummyBusList.end(); it != itEnd; ++it) {
884 dummyBusList.clear();
888 bool clockwise =
true;
890 numRot = std::abs(numRot);
893 for (
int i = 0; i < numRot; i++)
Rotate(clockwise);
895 auto electricalProp = elementNode->first_node(
"ElectricalProperties");
896 if (!electricalProp)
return false;
898 SetOnline(XMLParser::GetNodeValueInt(electricalProp,
"IsOnline"));
899 m_electricalData.name = electricalProp->first_node(
"Name")->value();
900 m_electricalData.primaryNominalVoltage = XMLParser::GetNodeValueDouble(electricalProp,
"PrimaryNominalVoltage");
901 m_electricalData.primaryNominalVoltageUnit =
902 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"PrimaryNominalVoltage",
"UnitID"));
903 m_electricalData.secondaryNominalVoltage = XMLParser::GetNodeValueDouble(electricalProp,
"SecondaryNominalVoltage");
904 m_electricalData.secondaryNominalVoltageUnit =
static_cast<ElectricalUnit>(
905 XMLParser::GetAttributeValueInt(electricalProp,
"SecondaryNominalVoltage",
"UnitID"));
906 m_electricalData.nominalPower = XMLParser::GetNodeValueDouble(electricalProp,
"NominalPower");
907 m_electricalData.nominalPowerUnit =
908 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"NominalPower",
"UnitID"));
909 m_electricalData.resistance = XMLParser::GetNodeValueDouble(electricalProp,
"Resistance");
910 m_electricalData.resistanceUnit =
911 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"Resistance",
"UnitID"));
912 m_electricalData.indReactance = XMLParser::GetNodeValueDouble(electricalProp,
"IndReactance");
913 m_electricalData.indReactanceUnit =
914 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"IndReactance",
"UnitID"));
915 m_electricalData.connection = (TransformerConnection)XMLParser::GetNodeValueInt(electricalProp,
"Connection");
916 m_electricalData.turnsRatio = XMLParser::GetNodeValueDouble(electricalProp,
"TurnsRatio");
917 m_electricalData.phaseShift = XMLParser::GetNodeValueDouble(electricalProp,
"PhaseShift");
918 m_electricalData.useTransformerPower = XMLParser::GetNodeValueInt(electricalProp,
"UseTransfomerPower");
920 auto fault = electricalProp->first_node(
"Fault");
921 m_electricalData.zeroResistance = XMLParser::GetNodeValueDouble(fault,
"ZeroResistance");
922 m_electricalData.zeroIndReactance = XMLParser::GetNodeValueDouble(fault,
"ZeroIndReactance");
923 m_electricalData.primaryGrndResistance = XMLParser::GetNodeValueDouble(fault,
"PrimaryGrndResistance");
924 m_electricalData.primaryGrndReactance = XMLParser::GetNodeValueDouble(fault,
"PrimaryGrndReactance");
925 m_electricalData.secondaryGrndResistance = XMLParser::GetNodeValueDouble(fault,
"SecondaryGrndResistance");
926 m_electricalData.secondaryGrndReactance = XMLParser::GetNodeValueDouble(fault,
"SecondaryGrndReactance");
928 if (!OpenSwitchingData(electricalProp))
return false;
934void Transformer::SetBestPositionAndRotation()
936 wxPoint2DDouble p1 = m_pointList[0];
937 wxPoint2DDouble p2 = m_pointList[m_pointList.size() - 1];
938 wxPoint2DDouble mid = (p1 + p2) / 2.0;
941 double bestAngle = wxRadToDeg(std::atan2(p2.m_y - p1.m_y, p2.m_x - p1.m_x));
942 bool clockwise = bestAngle > 0 ? true :
false;
943 while (std::abs(m_angle) < std::abs(bestAngle)) {
Rotate(clockwise); }
ElectricalUnit
Electrical units.
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 DrawDCSwitches(wxGraphicsContext *gc) const
Draw switch.
virtual void DrawDCPowerFlowPts(wxGraphicsContext *gc) const
Draw power flow arrows.
virtual wxPoint2DDouble GetSwitchPoint(Element *parent, wxPoint2DDouble parentPoint, wxPoint2DDouble secondPoint) const
Get the correct switch position.
std::vector< double > swTime