19#include "../../utils/Path.h"
23 m_elementType = TYPE_LINE;
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); }
29Line::Line(wxString name) :
Branch()
31 m_elementType = TYPE_LINE;
32 for (
int i = 0; i < 2; i++) {
33 for (
int j = 0; j < 3; j++) { m_electricalData.faultCurrent[i][j] = std::complex<double>(0.0, 0.0); }
35 m_electricalData.name = name;
108void Line::DrawDC(wxPoint2DDouble translation,
double scale, wxGraphicsContext* gc)
const
112 wxGraphicsMatrix identityMatrix = gc->GetTransform();
113 identityMatrix.Set();
115 wxColour elementColour;
118 elementColour = m_dynamicEventColour;
120 elementColour = m_onlineElementColour;
124 elementColour = m_offlineElementColour;
126 std::vector<wxPoint2DDouble> pointList = m_pointList;
127 if (!m_inserted && pointList.size() > 0) {
128 wxPoint2DDouble secondPoint = m_position;
129 if (pointList.size() > 2) { secondPoint = pointList[2]; }
130 pointList[1] =
GetSwitchPoint(m_parentList[0], pointList[0], secondPoint);
131 pointList.push_back(m_position);
136 gc->SetPen(wxPen(m_selectionColour, 2 + m_borderSize * 2.0));
137 gc->SetBrush(*wxTRANSPARENT_BRUSH);
138 if (pointList.size() > 0)
139 gc->StrokeLines(pointList.size(), &pointList[0]);
142 gc->SetPen(*wxTRANSPARENT_PEN);
143 gc->SetBrush(wxBrush(m_selectionColour));
144 if (pointList.size() > 0) {
145 DrawDCCircle(pointList[0], 5.0 + m_borderSize / scale, 10, gc);
146 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0 + m_borderSize / scale, 10, gc); }
151 gc->SetPen(wxPen(elementColour, 2));
152 gc->SetBrush(*wxTRANSPARENT_BRUSH);
153 if (pointList.size() > 0)
154 gc->StrokeLines(pointList.size(), &pointList[0]);
162 gc->SetPen(*wxTRANSPARENT_PEN);
163 gc->SetBrush(wxBrush(elementColour));
164 if (pointList.size() > 0) {
166 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0, 10, gc); }
172 gc->SetTransform(identityMatrix);
174 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) {
182void Line::DrawDC(wxPoint2DDouble translation,
double scale, wxDC& dc)
const
185 wxColour elementColour;
188 elementColour = m_dynamicEventColour;
190 elementColour = m_onlineElementColour;
194 elementColour = m_offlineElementColour;
196 std::vector<wxPoint> pointList;
197 for (
auto pt : m_pointList) {
198 pointList.emplace_back(pt.m_x, pt.m_y);
210 dc.SetPen(wxPen(m_selectionColour, 2 + m_borderSize * 2.0));
211 dc.SetBrush(*wxTRANSPARENT_BRUSH);
212 if (pointList.size() > 0)
213 dc.DrawLines(pointList.size(), &pointList[0]);
216 dc.SetPen(*wxTRANSPARENT_PEN);
217 dc.SetBrush(wxBrush(m_selectionColour));
218 if (pointList.size() > 0) {
219 DrawDCCircle(pointList[0], 5.0 + m_borderSize / scale, dc);
220 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0 + m_borderSize / scale, dc); }
225 dc.SetPen(wxPen(elementColour, 2));
226 dc.SetBrush(*wxTRANSPARENT_BRUSH);
227 if (pointList.size() > 0)
228 dc.DrawLines(pointList.size(), &pointList[0]);
236 dc.SetPen(*wxTRANSPARENT_PEN);
237 dc.SetBrush(wxBrush(elementColour));
238 if (pointList.size() > 0) {
240 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0, dc); }
258 if (!m_parentList[0]) {
259 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
260 UpdateSwitchesPosition();
261 UpdatePowerFlowArrowsPosition();
263 if (!m_parentList[1]) {
264 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
265 UpdateSwitchesPosition();
266 UpdatePowerFlowArrowsPosition();
269 if (!m_parentList[0] && !m_parentList[1]) {
270 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) {
271 m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
280 if (m_parentList.size() == 0) {
281 m_position = position;
282 m_parentList.push_back(parent);
284 wxPoint2DDouble parentPt =
288 m_pointList.push_back(parentPt);
289 m_pointList.push_back(
GetSwitchPoint(parent, parentPt, m_position));
291 wxRect2DDouble genRect(0, 0, 0, 0);
292 m_switchRect.push_back(genRect);
295 Bus* parentBus =
static_cast<Bus*
>(parent);
296 m_electricalData.nominalVoltage = parentBus->GetElectricalData().nominalVoltage;
297 m_electricalData.nominalVoltageUnit = parentBus->GetElectricalData().nominalVoltageUnit;
302 else if (parent != m_parentList[0]) {
303 Bus* parentBus =
static_cast<Bus*
>(parent);
304 if (m_electricalData.nominalVoltage != parentBus->GetElectricalData().nominalVoltage ||
305 m_electricalData.nominalVoltageUnit != parentBus->GetElectricalData().nominalVoltageUnit) {
306 wxMessageDialog msgDialog(
nullptr,
307 _(
"Unable to connect two buses with different nominal voltages.\n"
308 "Use a transformer or edit the bus properties."),
309 _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
310 msgDialog.ShowModal();
314 m_parentList.push_back(parent);
316 wxPoint2DDouble parentPt =
322 wxPoint2DDouble secondPoint = parentPt;
323 if (m_pointList.size() > 2) { secondPoint = m_pointList[2]; }
324 m_pointList[1] =
GetSwitchPoint(m_parentList[0], m_pointList[0], secondPoint);
327 m_pointList.push_back(
GetSwitchPoint(parent, parentPt, m_pointList[m_pointList.size() - 1]));
329 m_pointList.push_back(parentPt);
331 wxRect2DDouble genRect(0, 0, 0, 0);
332 m_switchRect.push_back(genRect);
336 UpdatePowerFlowArrowsPosition();
344 for (
auto it = m_pointList.begin(); it != m_pointList.end(); ++it) {
345 if (rect.Contains(*it))
return true;
353 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) {
354 if (m_activePickboxID == i) {
355 m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
356 UpdateSwitchesPosition();
357 UpdatePowerFlowArrowsPosition();
363 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) {
364 wxRect2DDouble rect(m_pointList[i].m_x - 5.0, m_pointList[i].m_y - 5.0, 10.0, 10.0);
365 if (rect.Contains(position)) {
366 m_activePickboxID = i;
375 if (m_parentList.size() != 0) { m_pointList.push_back(point); }
380 m_moveStartPt = position;
381 m_movePts = m_pointList;
388 if (parent == m_parentList[0]) {
389 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
392 else if (parent == m_parentList[1]) {
393 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
398 for (
int i = 2; i < (int)m_pointList.size() - 1; i++) {
399 m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
405 if (m_activeNodeID == 1) {
406 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
407 if (m_parentList[0]) {
408 m_parentList[0]->RemoveChild(
this);
409 m_parentList[0] =
nullptr;
413 else if (m_activeNodeID == 2) {
414 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
415 if (m_parentList[1]) {
416 m_parentList[1]->RemoveChild(
this);
417 m_parentList[1] =
nullptr;
424 UpdateSwitchesPosition();
425 UpdatePowerFlowArrowsPosition();
435 wxString busName[2] = {
"?",
"?" };
436 if (m_parentList.size() == 2) {
438 for (
Element* element : m_parentList) {
440 Bus* bus =
static_cast<Bus*
>(element);
441 busName[i] = bus->GetElectricalData().name;
447 wxMenu* textMenu =
new wxMenu();
449 textMenu->Append(ID_TXT_NAME, _(
"Name"));
450 textMenu->Append(ID_TXT_BRANCH_ACTIVE_POWER_1_2, _(
"Active power (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
451 textMenu->Append(ID_TXT_BRANCH_ACTIVE_POWER_2_1, _(
"Active power (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
452 textMenu->Append(ID_TXT_BRANCH_REACTIVE_POWER_1_2, _(
"Reactive power (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
453 textMenu->Append(ID_TXT_BRANCH_REACTIVE_POWER_2_1, _(
"Reactive power (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
454 textMenu->Append(ID_TXT_BRANCH_LOSSES, _(
"Losses"));
455 textMenu->Append(ID_TXT_BRANCH_CURRENT_1_2, _(
"Current (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
456 textMenu->Append(ID_TXT_BRANCH_CURRENT_2_1, _(
"Current (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
457 textMenu->Append(ID_TXT_BRANCH_FAULT_CURRENT_1_2, _(
"Fault current (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
458 textMenu->Append(ID_TXT_BRANCH_FAULT_CURRENT_2_1, _(
"Fault current (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
459 textMenu->SetClientData(menu.GetClientData());
460 menu.AppendSubMenu(textMenu, _(
"Add text"));
463 wxMenuItem* addNodeItem =
new wxMenuItem(&menu,
ID_LINE_ADD_NODE, _(
"Insert node"));
464 addNodeItem->SetBitmap(wxImage(Paths::GetDataPath() +
"/images/menu/addNode16.png"));
465 menu.Append(addNodeItem);
469 addNodeItem->SetBitmap(wxImage(Paths::GetDataPath() +
"/images/menu/removeNode16.png"));
470 menu.Append(addNodeItem);
472 wxMenuItem* deleteItem =
new wxMenuItem(&menu,
ID_DELETE, _(
"Delete"));
473 deleteItem->SetBitmap(wxImage(Paths::GetDataPath() +
"/images/menu/delete16.png"));
474 menu.Append(deleteItem);
478void Line::RemoveNode(wxPoint2DDouble point)
481 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) {
482 if (m_activePickboxID == i) {
483 m_pointList.erase(m_pointList.begin() + i);
488 UpdateSwitchesPosition();
489 UpdatePowerFlowArrowsPosition();
492void Line::AddNode(wxPoint2DDouble point)
494 int segmentNumber = 0;
496 if (segmentNumber > 0 && segmentNumber < (
int)m_pointList.size() - 2) {
497 m_pointList.insert(m_pointList.begin() + segmentNumber + 1, point);
499 UpdateSwitchesPosition();
500 UpdatePowerFlowArrowsPosition();
505 if (m_pointList.size() > 0) {
507 leftUp = m_pointList[0];
508 rightBottom = m_pointList[0];
509 for (
int i = 1; i < (int)m_pointList.size(); i++) {
510 if (m_pointList[i].m_x < leftUp.m_x) leftUp.m_x = m_pointList[i].m_x;
511 if (m_pointList[i].m_y < leftUp.m_y) leftUp.m_y = m_pointList[i].m_y;
512 if (m_pointList[i].m_x > rightBottom.m_x) rightBottom.m_x = m_pointList[i].m_x;
513 if (m_pointList[i].m_y > rightBottom.m_y) rightBottom.m_y = m_pointList[i].m_y;
521 lineForm.CenterOnParent();
522 if (lineForm.ShowModal() == wxID_OK) {
530 if (nominalVoltage.size() > 0) {
531 m_electricalData.nominalVoltage = nominalVoltage[0];
532 m_electricalData.nominalVoltageUnit = nominalVoltageUnit[0];
538 if (m_activeNodeID == 1 && parent == m_parentList[0])
return false;
539 if (m_activeNodeID == 2 && parent == m_parentList[1])
return false;
541 if (parent && m_activeNodeID != 0) {
542 wxRect2DDouble nodeRect(0, 0, 0, 0);
543 if (m_activeNodeID == 1) {
544 nodeRect = wxRect2DDouble(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
545 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
547 if (m_activeNodeID == 2) {
548 nodeRect = wxRect2DDouble(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
549 m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize,
550 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
556 Bus* parentBus =
static_cast<Bus*
>(parent);
557 if (!m_parentList[0] && !m_parentList[1]) {
558 m_electricalData.nominalVoltage = parentBus->GetElectricalData().nominalVoltage;
559 m_electricalData.nominalVoltageUnit = parentBus->GetElectricalData().nominalVoltageUnit;
561 else if (m_electricalData.nominalVoltage != parentBus->GetElectricalData().nominalVoltage ||
562 m_electricalData.nominalVoltageUnit != parentBus->GetElectricalData().nominalVoltageUnit) {
563 wxMessageDialog msgDialog(
nullptr,
564 _(
"Unable to connect two buses with different nominal voltages.\n"
565 "Use a transformer or edit the bus properties."),
566 _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
567 msgDialog.ShowModal();
572 if (m_activeNodeID == 1) {
574 if (m_parentList[1] == parent) {
579 m_parentList[0] = parent;
583 m_pointList[0], -parent->
GetAngle());
586 m_pointList[0] = parentPt;
588 UpdateSwitchesPosition();
589 UpdatePowerFlowArrowsPosition();
592 if (m_activeNodeID == 2) {
593 if (m_parentList[0] == parent) {
598 m_parentList[1] = parent;
600 wxPoint2DDouble parentPt =
604 m_pointList[m_pointList.size() - 1] = parentPt;
606 UpdateSwitchesPosition();
607 UpdatePowerFlowArrowsPosition();
612 if (m_activeNodeID == 1) m_parentList[0] =
nullptr;
613 if (m_activeNodeID == 2) m_parentList[1] =
nullptr;
621 m_pfDirection = pfDirection;
622 UpdatePowerFlowArrowsPosition();
625void Line::UpdatePowerFlowArrowsPosition()
627 std::vector<wxPoint2DDouble> edges;
628 switch (m_pfDirection) {
630 m_powerFlowArrow.clear();
633 for (
int i = 1; i < (int)m_pointList.size() - 1; i++) { edges.push_back(m_pointList[i]); }
636 for (
int i = (
int)m_pointList.size() - 2; i > 0; i--) { edges.push_back(m_pointList[i]); }
646 double rotAngle = m_rotationAngle;
647 if (!clockwise) rotAngle = -m_rotationAngle;
649 if (parent == m_parentList[0]) {
652 else if (parent == m_parentList[1]) {
653 m_pointList[m_pointList.size() - 1] = parent->
RotateAtPosition(m_pointList[m_pointList.size() - 1], rotAngle);
655 UpdateSwitchesPosition();
656 UpdatePowerFlowArrowsPosition();
661 m_pointList = pointList;
662 UpdateSwitchesPosition();
663 UpdatePowerFlowArrowsPosition();
675 wxString tipText = m_electricalData.name;
680 busNumber[0] =
static_cast<Bus*
>(m_parentList[0])->GetElectricalData().number + 1;
681 busNumber[1] =
static_cast<Bus*
>(m_parentList[1])->GetElectricalData().number + 1;
683 tipText += _(
"\nP") + wxString::Format(
"(%d-%d) = ", busNumber[0], busNumber[1]) +
684 wxString::FromDouble(m_electricalData.powerFlow[0].real(), 5) + _(
" p.u.");
685 tipText += _(
"\nQ") + wxString::Format(
"(%d-%d) = ", busNumber[0], busNumber[1]) +
686 wxString::FromDouble(m_electricalData.powerFlow[0].imag(), 5) + _(
" p.u.");
687 tipText += _(
"\nP") + wxString::Format(
"(%d-%d) = ", busNumber[1], busNumber[0]) +
688 wxString::FromDouble(m_electricalData.powerFlow[1].real(), 5) + _(
" p.u.");
689 tipText += _(
"\nQ") + wxString::Format(
"(%d-%d) = ", busNumber[1], busNumber[0]) +
690 wxString::FromDouble(m_electricalData.powerFlow[1].imag(), 5) + _(
" p.u.");
692 if (!m_electricalData.harmonicOrder.empty()) {
693 tipText += _(
"\n\nHarmonic currents:");
695 for (
auto& hCurrent1 : m_electricalData.harmonicCurrent[0]) {
696 auto& hCurrent2 = m_electricalData.harmonicCurrent[1][i];
698 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'));
699 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'));
714 data.nominalPower = m_electricalData.nominalPower;
715 data.nominalPowerUnit = m_electricalData.nominalPowerUnit;
717 data.nominalVoltage = m_electricalData.nominalVoltage;
718 data.nominalVoltageUnit = m_electricalData.nominalVoltageUnit;
720 data.useLinePower = m_electricalData.useLinePower;
722 data.lineSize = m_electricalData.lineSize;
724 data.resistance = m_electricalData.resistance;
725 data.resistanceUnit = m_electricalData.resistanceUnit;
727 data.indReactance = m_electricalData.indReactance;
728 data.indReactanceUnit = m_electricalData.indReactanceUnit;
730 data.capSusceptance = m_electricalData.capSusceptance;
731 data.capSusceptanceUnit = m_electricalData.capSusceptanceUnit;
733 data.zeroResistance = m_electricalData.zeroResistance;
734 data.zeroIndReactance = m_electricalData.zeroIndReactance;
735 data.zeroCapSusceptance = m_electricalData.zeroCapSusceptance;
737 data.powerFlow[0] = m_electricalData.powerFlow[0];
738 data.powerFlow[1] = m_electricalData.powerFlow[1];
740 double lineBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
741 double baseVoltage = GetValueFromUnit(data.nominalVoltage, data.nominalVoltageUnit);
742 double systemBaseImpedance = (baseVoltage * baseVoltage) / systemBasePower;
743 double lineBaseImpedance = (baseVoltage * baseVoltage) / lineBasePower;
746 double r = data.resistance;
749 if (data.useLinePower) data.resistance = (r * lineBaseImpedance) / systemBaseImpedance;
752 data.resistance = r / systemBaseImpedance;
757 double x = data.indReactance;
760 if (data.useLinePower) data.indReactance = (x * lineBaseImpedance) / systemBaseImpedance;
763 data.indReactance = x / systemBaseImpedance;
768 double b = data.capSusceptance;
771 if (data.useLinePower) data.capSusceptance = (b / lineBaseImpedance) * systemBaseImpedance;
774 data.capSusceptance = b * systemBaseImpedance;
781 double r0 = data.zeroResistance;
782 if (data.useLinePower) data.zeroResistance = (r0 * lineBaseImpedance) / systemBaseImpedance;
785 double x0 = data.zeroIndReactance;
786 if (data.useLinePower) data.zeroIndReactance = (x0 * lineBaseImpedance) / systemBaseImpedance;
789 double b0 = data.zeroCapSusceptance;
790 if (data.useLinePower) data.zeroCapSusceptance = (b0 / lineBaseImpedance) * systemBaseImpedance;
793 data.powerFlow[0] = std::complex<double>(0, 0);
794 data.powerFlow[1] = std::complex<double>(0, 0);
795 data.faultCurrent[0][0] = std::complex<double>(0, 0);
796 data.faultCurrent[0][1] = std::complex<double>(0, 0);
797 data.faultCurrent[0][2] = std::complex<double>(0, 0);
798 data.faultCurrent[1][0] = std::complex<double>(0, 0);
799 data.faultCurrent[1][1] = std::complex<double>(0, 0);
800 data.faultCurrent[1][2] = std::complex<double>(0, 0);
806rapidxml::xml_node<>* Line::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
808 auto elementNode = XMLParser::AppendNode(doc, elementListNode,
"Line");
809 XMLParser::SetNodeAttribute(doc, elementNode,
"ID", m_elementID);
810 auto cadProp = XMLParser::AppendNode(doc, elementNode,
"CADProperties");
811 auto nodeList = XMLParser::AppendNode(doc, cadProp,
"NodeList");
814 for (
unsigned int i = 0; i < m_pointList.size(); i++) {
817 if ((i != 1) && (i != m_pointList.size() - 2)) {
818 auto nodePos = XMLParser::AppendNode(doc, nodeList,
"Node");
819 XMLParser::SetNodeAttribute(doc, nodePos,
"ID", nodeID);
820 auto nodePosX = XMLParser::AppendNode(doc, nodePos,
"X");
821 XMLParser::SetNodeValue(doc, nodePosX, m_pointList[i].m_x);
822 auto nodePosY = XMLParser::AppendNode(doc, nodePos,
"Y");
823 XMLParser::SetNodeValue(doc, nodePosY, m_pointList[i].m_y);
828 auto parentIDList = XMLParser::AppendNode(doc, cadProp,
"ParentIDList");
829 for (
unsigned int i = 0; i < m_parentList.size(); i++) {
830 if (m_parentList[i]) {
831 auto parentID = XMLParser::AppendNode(doc, parentIDList,
"ParentID");
832 XMLParser::SetNodeAttribute(doc, parentID,
"ID",
static_cast<int>(i));
833 XMLParser::SetNodeValue(doc, parentID, m_parentList[i]->
GetID());
837 auto electricalProp = XMLParser::AppendNode(doc, elementNode,
"ElectricalProperties");
838 auto isOnline = XMLParser::AppendNode(doc, electricalProp,
"IsOnline");
839 XMLParser::SetNodeValue(doc, isOnline, m_online);
840 auto name = XMLParser::AppendNode(doc, electricalProp,
"Name");
841 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
842 auto nominalVoltage = XMLParser::AppendNode(doc, electricalProp,
"NominalVoltage");
843 XMLParser::SetNodeValue(doc, nominalVoltage, m_electricalData.nominalVoltage);
844 XMLParser::SetNodeAttribute(doc, nominalVoltage,
"UnitID",
static_cast<int>(m_electricalData.nominalVoltageUnit));
845 auto nominalPower = XMLParser::AppendNode(doc, electricalProp,
"NominalPower");
846 XMLParser::SetNodeValue(doc, nominalPower, m_electricalData.nominalPower);
847 XMLParser::SetNodeAttribute(doc, nominalPower,
"UnitID",
static_cast<int>(m_electricalData.nominalPowerUnit));
848 auto resistance = XMLParser::AppendNode(doc, electricalProp,
"Resistance");
849 XMLParser::SetNodeValue(doc, resistance, m_electricalData.resistance);
850 XMLParser::SetNodeAttribute(doc, resistance,
"UnitID",
static_cast<int>(m_electricalData.resistanceUnit));
851 auto indReactance = XMLParser::AppendNode(doc, electricalProp,
"IndReactance");
852 XMLParser::SetNodeValue(doc, indReactance, m_electricalData.indReactance);
853 XMLParser::SetNodeAttribute(doc, indReactance,
"UnitID",
static_cast<int>(m_electricalData.indReactanceUnit));
854 auto capSusceptance = XMLParser::AppendNode(doc, electricalProp,
"CapSusceptance");
855 XMLParser::SetNodeValue(doc, capSusceptance, m_electricalData.capSusceptance);
856 XMLParser::SetNodeAttribute(doc, capSusceptance,
"UnitID",
static_cast<int>(m_electricalData.capSusceptanceUnit));
857 auto lineSize = XMLParser::AppendNode(doc, electricalProp,
"LineSize");
858 XMLParser::SetNodeValue(doc, lineSize, m_electricalData.lineSize);
859 auto useLinePower = XMLParser::AppendNode(doc, electricalProp,
"UseLinePower");
860 XMLParser::SetNodeValue(doc, useLinePower, m_electricalData.useLinePower);
862 auto fault = XMLParser::AppendNode(doc, electricalProp,
"Fault");
863 auto zeroResistance = XMLParser::AppendNode(doc, fault,
"ZeroResistance");
864 XMLParser::SetNodeValue(doc, zeroResistance, m_electricalData.zeroResistance);
865 auto zeroIndReactance = XMLParser::AppendNode(doc, fault,
"ZeroIndReactance");
866 XMLParser::SetNodeValue(doc, zeroIndReactance, m_electricalData.zeroIndReactance);
867 auto zeroCapSusceptance = XMLParser::AppendNode(doc, fault,
"ZeroCapSusceptance");
868 XMLParser::SetNodeValue(doc, zeroCapSusceptance, m_electricalData.zeroCapSusceptance);
870 SaveSwitchingData(doc, electricalProp);
875bool Line::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
877 auto cadPropNode = elementNode->first_node(
"CADProperties");
878 if (!cadPropNode)
return false;
881 std::vector<wxPoint2DDouble> ptsList;
882 auto nodePosList = cadPropNode->first_node(
"NodeList");
883 if (!nodePosList)
return false;
884 auto nodePos = nodePosList->first_node(
"Node");
886 double nodePosX = XMLParser::GetNodeValueDouble(nodePos,
"X");
887 double nodePosY = XMLParser::GetNodeValueDouble(nodePos,
"Y");
888 ptsList.push_back(wxPoint2DDouble(nodePosX, nodePosY));
889 nodePos = nodePos->next_sibling(
"Node");
893 auto parentIDList = cadPropNode->first_node(
"ParentIDList");
894 if (!parentIDList)
return false;
895 auto parentNode = parentIDList->first_node(
"ParentID");
896 long parentID[2] = { -1, -1 };
899 wxString(parentNode->first_attribute(
"ID")->value()).ToCLong(&index);
900 wxString(parentNode->value()).ToCLong(&parentID[index]);
901 parentNode = parentNode->next_sibling(
"ParentID");
904 std::vector<wxPoint2DDouble> nodePtsList;
905 nodePtsList.push_back(ptsList[0]);
906 nodePtsList.push_back(ptsList[ptsList.size() - 1]);
909 std::vector<Bus*> dummyBusList;
910 for (
unsigned int i = 0; i < nodePtsList.size(); ++i) {
911 if (parentID[i] == -1)
913 Bus* dummyBus =
new Bus(nodePtsList[i]);
914 dummyBusList.push_back(dummyBus);
918 AddParent(parentList[parentID[i]], nodePtsList[i]);
923 std::vector<wxPoint2DDouble> midPts;
924 for (
unsigned int i = 1; i < ptsList.size() - 1; i++) midPts.push_back(ptsList[i]);
925 m_pointList.insert(m_pointList.begin() + 2, midPts.begin(), midPts.end());
929 for (
auto it = dummyBusList.begin(), itEnd = dummyBusList.end(); it != itEnd; ++it) {
933 dummyBusList.clear();
935 auto electricalProp = elementNode->first_node(
"ElectricalProperties");
936 if (!electricalProp)
return false;
938 SetOnline(XMLParser::GetNodeValueInt(electricalProp,
"IsOnline"));
939 m_electricalData.name = electricalProp->first_node(
"Name")->value();
940 m_electricalData.nominalVoltage = XMLParser::GetNodeValueDouble(electricalProp,
"NominalVoltage");
941 m_electricalData.nominalVoltageUnit =
942 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"NominalVoltage",
"UnitID"));
943 m_electricalData.nominalPower = XMLParser::GetNodeValueDouble(electricalProp,
"NominalPower");
944 m_electricalData.nominalPowerUnit =
945 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"NominalPower",
"UnitID"));
946 m_electricalData.resistance = XMLParser::GetNodeValueDouble(electricalProp,
"Resistance");
947 m_electricalData.resistanceUnit =
948 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"Resistance",
"UnitID"));
949 m_electricalData.indReactance = XMLParser::GetNodeValueDouble(electricalProp,
"IndReactance");
950 m_electricalData.indReactanceUnit =
951 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"IndReactance",
"UnitID"));
952 m_electricalData.capSusceptance = XMLParser::GetNodeValueDouble(electricalProp,
"CapSusceptance");
953 m_electricalData.capSusceptanceUnit =
954 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"CapSusceptance",
"UnitID"));
955 m_electricalData.lineSize = XMLParser::GetNodeValueDouble(electricalProp,
"LineSize");
956 m_electricalData.useLinePower = XMLParser::GetNodeValueInt(electricalProp,
"UseLinePower");
958 auto fault = electricalProp->first_node(
"Fault");
959 m_electricalData.zeroResistance = XMLParser::GetNodeValueDouble(fault,
"ZeroResistance");
960 m_electricalData.zeroIndReactance = XMLParser::GetNodeValueDouble(fault,
"ZeroIndReactance");
961 m_electricalData.zeroCapSusceptance = XMLParser::GetNodeValueDouble(fault,
"ZeroCapSusceptance");
963 if (!OpenSwitchingData(electricalProp))
return false;
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 Intersects(wxRect2DDouble rect) const =0
Check if the element's rect intersects other rect.
virtual int GetID() const
Get the element ID.
virtual double PointToLineDistance(wxPoint2DDouble point, int *segmentNumber=nullptr) const
Calculate the distance between a line (formed by point list) and a point.
wxPoint2DDouble GetPosition() const
Get the element position.
double GetAngle() const
Get the element angle.
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
virtual void DrawDCPickbox(wxPoint2DDouble position, wxGraphicsContext *gc) const
Draw a point.
virtual wxPoint2DDouble WorldToScreen(wxPoint2DDouble translation, double scale, double offsetX=0.0, double offsetY=0.0) const
Convert the element position to screen position.
virtual void AddChild(Element *child)
Add a child to the child list.
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.
void SetInserted(bool inserted=true)
Set if the element is properly inserted in the workspace.
virtual void AddPoint(wxPoint2DDouble point)
Add point to the list of points that connect the element to the bus.
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element's rect intersects other rect.
virtual void SetNominalVoltage(std::vector< double > nominalVoltage, std::vector< ElectricalUnit > nominalVoltageUnit)
Set nominal voltage of the element.
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus,...
virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
virtual void Move(wxPoint2DDouble position)
Move the element other position.
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
virtual wxString GetTipText() const
Get the tip text.
virtual bool SetNodeParent(Element *parent)
Set a perent to the node. If all conditions are met, a new parent are added to the element and the po...
virtual bool ShowForm(wxWindow *parent, Element *element, wxWindow *workspace=nullptr)
Show element data form.
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
virtual void CalculateBoundaries(wxPoint2DDouble &leftUp, wxPoint2DDouble &rightBottom) const
Calculate the element boundaries.
virtual void RotateNode(Element *parent, bool clockwise=true)
Rotate a node.
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
virtual void MoveNode(Element *parent, wxPoint2DDouble position)
Move a node. StartMove(wxPoint2DDouble position) before start moving.
virtual bool PickboxContains(wxPoint2DDouble position)
Check if a pickbox contains a point. If contains the attributes related to pickbox movement will be c...
virtual void SetPointList(std::vector< wxPoint2DDouble > pointList)
Set the list of points that connect the element to the bus.
virtual void MovePickbox(wxPoint2DDouble position)
Move the pickbox.
virtual Element * GetCopy()
Get a the element copy.
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