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'));
713 double lineBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
714 double baseVoltage = GetValueFromUnit(data.nominalVoltage, data.nominalVoltageUnit);
715 double systemBaseImpedance = (baseVoltage * baseVoltage) / systemBasePower;
716 double lineBaseImpedance = (baseVoltage * baseVoltage) / lineBasePower;
719 double r = data.resistance;
722 if (data.useLinePower) data.resistance = (r * lineBaseImpedance) / systemBaseImpedance;
725 data.resistance = r / systemBaseImpedance;
730 double x = data.indReactance;
733 if (data.useLinePower) data.indReactance = (x * lineBaseImpedance) / systemBaseImpedance;
736 data.indReactance = x / systemBaseImpedance;
741 double b = data.capSusceptance;
744 if (data.useLinePower) data.capSusceptance = (b / lineBaseImpedance) * systemBaseImpedance;
747 data.capSusceptance = b * systemBaseImpedance;
754 double r0 = data.zeroResistance;
755 if (data.useLinePower) data.zeroResistance = (r0 * lineBaseImpedance) / systemBaseImpedance;
758 double x0 = data.zeroIndReactance;
759 if (data.useLinePower) data.zeroIndReactance = (x0 * lineBaseImpedance) / systemBaseImpedance;
762 double b0 = data.zeroCapSusceptance;
763 if (data.useLinePower) data.zeroCapSusceptance = (b0 / lineBaseImpedance) * systemBaseImpedance;
766 data.powerFlow[0] = std::complex<double>(0, 0);
767 data.powerFlow[1] = std::complex<double>(0, 0);
768 data.faultCurrent[0][0] = std::complex<double>(0, 0);
769 data.faultCurrent[0][1] = std::complex<double>(0, 0);
770 data.faultCurrent[0][2] = std::complex<double>(0, 0);
771 data.faultCurrent[1][0] = std::complex<double>(0, 0);
772 data.faultCurrent[1][1] = std::complex<double>(0, 0);
773 data.faultCurrent[1][2] = std::complex<double>(0, 0);
779rapidxml::xml_node<>* Line::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
781 auto elementNode = XMLParser::AppendNode(doc, elementListNode,
"Line");
782 XMLParser::SetNodeAttribute(doc, elementNode,
"ID", m_elementID);
783 auto cadProp = XMLParser::AppendNode(doc, elementNode,
"CADProperties");
784 auto nodeList = XMLParser::AppendNode(doc, cadProp,
"NodeList");
787 for (
unsigned int i = 0; i < m_pointList.size(); i++) {
790 if ((i != 1) && (i != m_pointList.size() - 2)) {
791 auto nodePos = XMLParser::AppendNode(doc, nodeList,
"Node");
792 XMLParser::SetNodeAttribute(doc, nodePos,
"ID", nodeID);
793 auto nodePosX = XMLParser::AppendNode(doc, nodePos,
"X");
794 XMLParser::SetNodeValue(doc, nodePosX, m_pointList[i].m_x);
795 auto nodePosY = XMLParser::AppendNode(doc, nodePos,
"Y");
796 XMLParser::SetNodeValue(doc, nodePosY, m_pointList[i].m_y);
801 auto parentIDList = XMLParser::AppendNode(doc, cadProp,
"ParentIDList");
802 for (
unsigned int i = 0; i < m_parentList.size(); i++) {
803 if (m_parentList[i]) {
804 auto parentID = XMLParser::AppendNode(doc, parentIDList,
"ParentID");
805 XMLParser::SetNodeAttribute(doc, parentID,
"ID",
static_cast<int>(i));
806 XMLParser::SetNodeValue(doc, parentID, m_parentList[i]->
GetID());
810 auto electricalProp = XMLParser::AppendNode(doc, elementNode,
"ElectricalProperties");
811 auto isOnline = XMLParser::AppendNode(doc, electricalProp,
"IsOnline");
812 XMLParser::SetNodeValue(doc, isOnline, m_online);
813 auto name = XMLParser::AppendNode(doc, electricalProp,
"Name");
814 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
815 auto nominalVoltage = XMLParser::AppendNode(doc, electricalProp,
"NominalVoltage");
816 XMLParser::SetNodeValue(doc, nominalVoltage, m_electricalData.nominalVoltage);
817 XMLParser::SetNodeAttribute(doc, nominalVoltage,
"UnitID",
static_cast<int>(m_electricalData.nominalVoltageUnit));
818 auto nominalPower = XMLParser::AppendNode(doc, electricalProp,
"NominalPower");
819 XMLParser::SetNodeValue(doc, nominalPower, m_electricalData.nominalPower);
820 XMLParser::SetNodeAttribute(doc, nominalPower,
"UnitID",
static_cast<int>(m_electricalData.nominalPowerUnit));
821 auto resistance = XMLParser::AppendNode(doc, electricalProp,
"Resistance");
822 XMLParser::SetNodeValue(doc, resistance, m_electricalData.resistance);
823 XMLParser::SetNodeAttribute(doc, resistance,
"UnitID",
static_cast<int>(m_electricalData.resistanceUnit));
824 auto indReactance = XMLParser::AppendNode(doc, electricalProp,
"IndReactance");
825 XMLParser::SetNodeValue(doc, indReactance, m_electricalData.indReactance);
826 XMLParser::SetNodeAttribute(doc, indReactance,
"UnitID",
static_cast<int>(m_electricalData.indReactanceUnit));
827 auto capSusceptance = XMLParser::AppendNode(doc, electricalProp,
"CapSusceptance");
828 XMLParser::SetNodeValue(doc, capSusceptance, m_electricalData.capSusceptance);
829 XMLParser::SetNodeAttribute(doc, capSusceptance,
"UnitID",
static_cast<int>(m_electricalData.capSusceptanceUnit));
830 auto lineSize = XMLParser::AppendNode(doc, electricalProp,
"LineSize");
831 XMLParser::SetNodeValue(doc, lineSize, m_electricalData.lineSize);
832 auto useLinePower = XMLParser::AppendNode(doc, electricalProp,
"UseLinePower");
833 XMLParser::SetNodeValue(doc, useLinePower, m_electricalData.useLinePower);
835 auto fault = XMLParser::AppendNode(doc, electricalProp,
"Fault");
836 auto zeroResistance = XMLParser::AppendNode(doc, fault,
"ZeroResistance");
837 XMLParser::SetNodeValue(doc, zeroResistance, m_electricalData.zeroResistance);
838 auto zeroIndReactance = XMLParser::AppendNode(doc, fault,
"ZeroIndReactance");
839 XMLParser::SetNodeValue(doc, zeroIndReactance, m_electricalData.zeroIndReactance);
840 auto zeroCapSusceptance = XMLParser::AppendNode(doc, fault,
"ZeroCapSusceptance");
841 XMLParser::SetNodeValue(doc, zeroCapSusceptance, m_electricalData.zeroCapSusceptance);
843 SaveSwitchingData(doc, electricalProp);
848bool Line::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
850 auto cadPropNode = elementNode->first_node(
"CADProperties");
851 if (!cadPropNode)
return false;
854 std::vector<wxPoint2DDouble> ptsList;
855 auto nodePosList = cadPropNode->first_node(
"NodeList");
856 if (!nodePosList)
return false;
857 auto nodePos = nodePosList->first_node(
"Node");
859 double nodePosX = XMLParser::GetNodeValueDouble(nodePos,
"X");
860 double nodePosY = XMLParser::GetNodeValueDouble(nodePos,
"Y");
861 ptsList.push_back(wxPoint2DDouble(nodePosX, nodePosY));
862 nodePos = nodePos->next_sibling(
"Node");
866 auto parentIDList = cadPropNode->first_node(
"ParentIDList");
867 if (!parentIDList)
return false;
868 auto parentNode = parentIDList->first_node(
"ParentID");
869 long parentID[2] = { -1, -1 };
872 wxString(parentNode->first_attribute(
"ID")->value()).ToCLong(&index);
873 wxString(parentNode->value()).ToCLong(&parentID[index]);
874 parentNode = parentNode->next_sibling(
"ParentID");
877 std::vector<wxPoint2DDouble> nodePtsList;
878 nodePtsList.push_back(ptsList[0]);
879 nodePtsList.push_back(ptsList[ptsList.size() - 1]);
882 std::vector<Bus*> dummyBusList;
883 for (
unsigned int i = 0; i < nodePtsList.size(); ++i) {
884 if (parentID[i] == -1)
886 Bus* dummyBus =
new Bus(nodePtsList[i]);
887 dummyBusList.push_back(dummyBus);
891 AddParent(parentList[parentID[i]], nodePtsList[i]);
896 std::vector<wxPoint2DDouble> midPts;
897 for (
unsigned int i = 1; i < ptsList.size() - 1; i++) midPts.push_back(ptsList[i]);
898 m_pointList.insert(m_pointList.begin() + 2, midPts.begin(), midPts.end());
902 for (
auto it = dummyBusList.begin(), itEnd = dummyBusList.end(); it != itEnd; ++it) {
906 dummyBusList.clear();
908 auto electricalProp = elementNode->first_node(
"ElectricalProperties");
909 if (!electricalProp)
return false;
911 SetOnline(XMLParser::GetNodeValueInt(electricalProp,
"IsOnline"));
912 m_electricalData.name = electricalProp->first_node(
"Name")->value();
913 m_electricalData.nominalVoltage = XMLParser::GetNodeValueDouble(electricalProp,
"NominalVoltage");
914 m_electricalData.nominalVoltageUnit =
915 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"NominalVoltage",
"UnitID"));
916 m_electricalData.nominalPower = XMLParser::GetNodeValueDouble(electricalProp,
"NominalPower");
917 m_electricalData.nominalPowerUnit =
918 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"NominalPower",
"UnitID"));
919 m_electricalData.resistance = XMLParser::GetNodeValueDouble(electricalProp,
"Resistance");
920 m_electricalData.resistanceUnit =
921 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"Resistance",
"UnitID"));
922 m_electricalData.indReactance = XMLParser::GetNodeValueDouble(electricalProp,
"IndReactance");
923 m_electricalData.indReactanceUnit =
924 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"IndReactance",
"UnitID"));
925 m_electricalData.capSusceptance = XMLParser::GetNodeValueDouble(electricalProp,
"CapSusceptance");
926 m_electricalData.capSusceptanceUnit =
927 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"CapSusceptance",
"UnitID"));
928 m_electricalData.lineSize = XMLParser::GetNodeValueDouble(electricalProp,
"LineSize");
929 m_electricalData.useLinePower = XMLParser::GetNodeValueInt(electricalProp,
"UseLinePower");
931 auto fault = electricalProp->first_node(
"Fault");
932 m_electricalData.zeroResistance = XMLParser::GetNodeValueDouble(fault,
"ZeroResistance");
933 m_electricalData.zeroIndReactance = XMLParser::GetNodeValueDouble(fault,
"ZeroIndReactance");
934 m_electricalData.zeroCapSusceptance = XMLParser::GetNodeValueDouble(fault,
"ZeroCapSusceptance");
936 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 ShowForm(wxWindow *parent, Element *element)
Show element data form.
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 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