22 m_elementType = TYPE_LINE;
23 for (
int i = 0; i < 2; i++) {
24 for (
int j = 0; j < 3; j++) { m_electricalData.faultCurrent[i][j] = std::complex<double>(0.0, 0.0); }
28Line::Line(wxString name) :
Branch()
30 m_elementType = TYPE_LINE;
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;
107void Line::DrawDC(wxPoint2DDouble translation,
double scale, wxGraphicsContext* gc)
const
111 wxGraphicsMatrix identityMatrix = gc->GetTransform();
112 identityMatrix.Set();
114 wxColour elementColour;
117 elementColour = m_dynamicEventColour;
119 elementColour = m_onlineElementColour;
123 elementColour = m_offlineElementColour;
125 std::vector<wxPoint2DDouble> pointList = m_pointList;
126 if (!m_inserted && pointList.size() > 0) {
127 wxPoint2DDouble secondPoint = m_position;
128 if (pointList.size() > 2) { secondPoint = pointList[2]; }
129 pointList[1] =
GetSwitchPoint(m_parentList[0], pointList[0], secondPoint);
130 pointList.push_back(m_position);
135 gc->SetPen(wxPen(m_selectionColour, 2 + m_borderSize * 2.0));
136 gc->SetBrush(*wxTRANSPARENT_BRUSH);
137 if (pointList.size() > 0)
138 gc->StrokeLines(pointList.size(), &pointList[0]);
141 gc->SetPen(*wxTRANSPARENT_PEN);
142 gc->SetBrush(wxBrush(m_selectionColour));
143 if (pointList.size() > 0) {
144 DrawDCCircle(pointList[0], 5.0 + m_borderSize / scale, 10, gc);
145 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0 + m_borderSize / scale, 10, gc); }
150 gc->SetPen(wxPen(elementColour, 2));
151 gc->SetBrush(*wxTRANSPARENT_BRUSH);
152 if (pointList.size() > 0)
153 gc->StrokeLines(pointList.size(), &pointList[0]);
161 gc->SetPen(*wxTRANSPARENT_PEN);
162 gc->SetBrush(wxBrush(elementColour));
163 if (pointList.size() > 0) {
165 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0, 10, gc); }
171 gc->SetTransform(identityMatrix);
173 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) {
181void Line::DrawDC(wxPoint2DDouble translation,
double scale, wxDC& dc)
const
184 wxColour elementColour;
187 elementColour = m_dynamicEventColour;
189 elementColour = m_onlineElementColour;
193 elementColour = m_offlineElementColour;
195 std::vector<wxPoint> pointList;
196 for (
auto pt : m_pointList) {
197 pointList.emplace_back(pt.m_x, pt.m_y);
209 dc.SetPen(wxPen(m_selectionColour, 2 + m_borderSize * 2.0));
210 dc.SetBrush(*wxTRANSPARENT_BRUSH);
211 if (pointList.size() > 0)
212 dc.DrawLines(pointList.size(), &pointList[0]);
215 dc.SetPen(*wxTRANSPARENT_PEN);
216 dc.SetBrush(wxBrush(m_selectionColour));
217 if (pointList.size() > 0) {
218 DrawDCCircle(pointList[0], 5.0 + m_borderSize / scale, dc);
219 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0 + m_borderSize / scale, dc); }
224 dc.SetPen(wxPen(elementColour, 2));
225 dc.SetBrush(*wxTRANSPARENT_BRUSH);
226 if (pointList.size() > 0)
227 dc.DrawLines(pointList.size(), &pointList[0]);
235 dc.SetPen(*wxTRANSPARENT_PEN);
236 dc.SetBrush(wxBrush(elementColour));
237 if (pointList.size() > 0) {
239 if (m_inserted) {
DrawDCCircle(pointList[pointList.size() - 1], 5.0, dc); }
257 if (!m_parentList[0]) {
258 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
259 UpdateSwitchesPosition();
260 UpdatePowerFlowArrowsPosition();
262 if (!m_parentList[1]) {
263 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
264 UpdateSwitchesPosition();
265 UpdatePowerFlowArrowsPosition();
268 if (!m_parentList[0] && !m_parentList[1]) {
269 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) {
270 m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
279 if (m_parentList.size() == 0) {
280 m_position = position;
281 m_parentList.push_back(parent);
283 wxPoint2DDouble parentPt =
287 m_pointList.push_back(parentPt);
288 m_pointList.push_back(
GetSwitchPoint(parent, parentPt, m_position));
290 wxRect2DDouble genRect(0, 0, 0, 0);
291 m_switchRect.push_back(genRect);
294 Bus* parentBus =
static_cast<Bus*
>(parent);
295 m_electricalData.nominalVoltage = parentBus->GetElectricalData().nominalVoltage;
296 m_electricalData.nominalVoltageUnit = parentBus->GetElectricalData().nominalVoltageUnit;
301 else if (parent != m_parentList[0]) {
302 Bus* parentBus =
static_cast<Bus*
>(parent);
303 if (m_electricalData.nominalVoltage != parentBus->GetElectricalData().nominalVoltage ||
304 m_electricalData.nominalVoltageUnit != parentBus->GetElectricalData().nominalVoltageUnit) {
305 wxMessageDialog msgDialog(
nullptr,
306 _(
"Unable to connect two buses with different nominal voltages.\n"
307 "Use a transformer or edit the bus properties."),
308 _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
309 msgDialog.ShowModal();
313 m_parentList.push_back(parent);
315 wxPoint2DDouble parentPt =
321 wxPoint2DDouble secondPoint = parentPt;
322 if (m_pointList.size() > 2) { secondPoint = m_pointList[2]; }
323 m_pointList[1] =
GetSwitchPoint(m_parentList[0], m_pointList[0], secondPoint);
326 m_pointList.push_back(
GetSwitchPoint(parent, parentPt, m_pointList[m_pointList.size() - 1]));
328 m_pointList.push_back(parentPt);
330 wxRect2DDouble genRect(0, 0, 0, 0);
331 m_switchRect.push_back(genRect);
335 UpdatePowerFlowArrowsPosition();
343 for (
auto it = m_pointList.begin(); it != m_pointList.end(); ++it) {
344 if (rect.Contains(*it))
return true;
352 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) {
353 if (m_activePickboxID == i) {
354 m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
355 UpdateSwitchesPosition();
356 UpdatePowerFlowArrowsPosition();
362 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) {
363 wxRect2DDouble rect(m_pointList[i].m_x - 5.0, m_pointList[i].m_y - 5.0, 10.0, 10.0);
364 if (rect.Contains(position)) {
365 m_activePickboxID = i;
374 if (m_parentList.size() != 0) { m_pointList.push_back(point); }
379 m_moveStartPt = position;
380 m_movePts = m_pointList;
387 if (parent == m_parentList[0]) {
388 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
391 else if (parent == m_parentList[1]) {
392 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
397 for (
int i = 2; i < (int)m_pointList.size() - 1; i++) {
398 m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
404 if (m_activeNodeID == 1) {
405 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
406 if (m_parentList[0]) {
407 m_parentList[0]->RemoveChild(
this);
408 m_parentList[0] =
nullptr;
412 else if (m_activeNodeID == 2) {
413 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
414 if (m_parentList[1]) {
415 m_parentList[1]->RemoveChild(
this);
416 m_parentList[1] =
nullptr;
423 UpdateSwitchesPosition();
424 UpdatePowerFlowArrowsPosition();
429 wxFileName exeFileName(wxStandardPaths::Get().GetExecutablePath());
430 wxString exePath = exeFileName.GetPath();
434 wxString busName[2] = {
"?",
"?" };
435 if (m_parentList.size() == 2) {
437 for (
Element* element : m_parentList) {
439 Bus* bus =
static_cast<Bus*
>(element);
440 busName[i] = bus->GetElectricalData().name;
446 wxMenu* textMenu =
new wxMenu();
448 textMenu->Append(ID_TXT_NAME, _(
"Name"));
449 textMenu->Append(ID_TXT_BRANCH_ACTIVE_POWER_1_2, _(
"Active power (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
450 textMenu->Append(ID_TXT_BRANCH_ACTIVE_POWER_2_1, _(
"Active power (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
451 textMenu->Append(ID_TXT_BRANCH_REACTIVE_POWER_1_2, _(
"Reactive power (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
452 textMenu->Append(ID_TXT_BRANCH_REACTIVE_POWER_2_1, _(
"Reactive power (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
453 textMenu->Append(ID_TXT_BRANCH_LOSSES, _(
"Losses"));
454 textMenu->Append(ID_TXT_BRANCH_CURRENT_1_2, _(
"Current (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
455 textMenu->Append(ID_TXT_BRANCH_CURRENT_2_1, _(
"Current (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
456 textMenu->Append(ID_TXT_BRANCH_FAULT_CURRENT_1_2, _(
"Fault current (") + busName[0] + _(
" to ") + busName[1] + wxT(
")"));
457 textMenu->Append(ID_TXT_BRANCH_FAULT_CURRENT_2_1, _(
"Fault current (") + busName[1] + _(
" to ") + busName[0] + wxT(
")"));
458 textMenu->SetClientData(menu.GetClientData());
459 menu.AppendSubMenu(textMenu, _(
"Add text"));
462 wxMenuItem* addNodeItem =
new wxMenuItem(&menu,
ID_LINE_ADD_NODE, _(
"Insert node"));
463 addNodeItem->SetBitmap(
464 wxImage(exePath + wxFileName::DirName(
"\\..\\data\\images\\menu\\addNode16.png", wxPATH_WIN).GetPath()));
465 menu.Append(addNodeItem);
469 addNodeItem->SetBitmap(
470 wxImage(exePath + wxFileName::DirName(
"\\..\\data\\images\\menu\\removeNode16.png", wxPATH_WIN).GetPath()));
471 menu.Append(addNodeItem);
473 wxMenuItem* deleteItem =
new wxMenuItem(&menu,
ID_DELETE, _(
"Delete"));
474 deleteItem->SetBitmap(
475 wxImage(exePath + wxFileName::DirName(
"\\..\\data\\images\\menu\\delete16.png", wxPATH_WIN).GetPath()));
476 menu.Append(deleteItem);
480void Line::RemoveNode(wxPoint2DDouble point)
483 for (
int i = 2; i < (int)m_pointList.size() - 2; i++) {
484 if (m_activePickboxID == i) {
485 m_pointList.erase(m_pointList.begin() + i);
490 UpdateSwitchesPosition();
491 UpdatePowerFlowArrowsPosition();
494void Line::AddNode(wxPoint2DDouble point)
496 int segmentNumber = 0;
498 if (segmentNumber > 0 && segmentNumber < (
int)m_pointList.size() - 2) {
499 m_pointList.insert(m_pointList.begin() + segmentNumber + 1, point);
501 UpdateSwitchesPosition();
502 UpdatePowerFlowArrowsPosition();
507 if (m_pointList.size() > 0) {
509 leftUp = m_pointList[0];
510 rightBottom = m_pointList[0];
511 for (
int i = 1; i < (int)m_pointList.size(); i++) {
512 if (m_pointList[i].m_x < leftUp.m_x) leftUp.m_x = m_pointList[i].m_x;
513 if (m_pointList[i].m_y < leftUp.m_y) leftUp.m_y = m_pointList[i].m_y;
514 if (m_pointList[i].m_x > rightBottom.m_x) rightBottom.m_x = m_pointList[i].m_x;
515 if (m_pointList[i].m_y > rightBottom.m_y) rightBottom.m_y = m_pointList[i].m_y;
523 lineForm.CenterOnParent();
524 if (lineForm.ShowModal() == wxID_OK) {
532 if (nominalVoltage.size() > 0) {
533 m_electricalData.nominalVoltage = nominalVoltage[0];
534 m_electricalData.nominalVoltageUnit = nominalVoltageUnit[0];
540 if (m_activeNodeID == 1 && parent == m_parentList[0])
return false;
541 if (m_activeNodeID == 2 && parent == m_parentList[1])
return false;
543 if (parent && m_activeNodeID != 0) {
544 wxRect2DDouble nodeRect(0, 0, 0, 0);
545 if (m_activeNodeID == 1) {
546 nodeRect = wxRect2DDouble(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
547 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
549 if (m_activeNodeID == 2) {
550 nodeRect = wxRect2DDouble(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
551 m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize,
552 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
558 Bus* parentBus =
static_cast<Bus*
>(parent);
559 if (!m_parentList[0] && !m_parentList[1]) {
560 m_electricalData.nominalVoltage = parentBus->GetElectricalData().nominalVoltage;
561 m_electricalData.nominalVoltageUnit = parentBus->GetElectricalData().nominalVoltageUnit;
563 else if (m_electricalData.nominalVoltage != parentBus->GetElectricalData().nominalVoltage ||
564 m_electricalData.nominalVoltageUnit != parentBus->GetElectricalData().nominalVoltageUnit) {
565 wxMessageDialog msgDialog(
nullptr,
566 _(
"Unable to connect two buses with different nominal voltages.\n"
567 "Use a transformer or edit the bus properties."),
568 _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
569 msgDialog.ShowModal();
574 if (m_activeNodeID == 1) {
576 if (m_parentList[1] == parent) {
581 m_parentList[0] = parent;
585 m_pointList[0], -parent->
GetAngle());
588 m_pointList[0] = parentPt;
590 UpdateSwitchesPosition();
591 UpdatePowerFlowArrowsPosition();
594 if (m_activeNodeID == 2) {
595 if (m_parentList[0] == parent) {
600 m_parentList[1] = parent;
602 wxPoint2DDouble parentPt =
606 m_pointList[m_pointList.size() - 1] = parentPt;
608 UpdateSwitchesPosition();
609 UpdatePowerFlowArrowsPosition();
614 if (m_activeNodeID == 1) m_parentList[0] =
nullptr;
615 if (m_activeNodeID == 2) m_parentList[1] =
nullptr;
623 m_pfDirection = pfDirection;
624 UpdatePowerFlowArrowsPosition();
627void Line::UpdatePowerFlowArrowsPosition()
629 std::vector<wxPoint2DDouble> edges;
630 switch (m_pfDirection) {
632 m_powerFlowArrow.clear();
635 for (
int i = 1; i < (int)m_pointList.size() - 1; i++) { edges.push_back(m_pointList[i]); }
638 for (
int i = (
int)m_pointList.size() - 2; i > 0; i--) { edges.push_back(m_pointList[i]); }
648 double rotAngle = m_rotationAngle;
649 if (!clockwise) rotAngle = -m_rotationAngle;
651 if (parent == m_parentList[0]) {
654 else if (parent == m_parentList[1]) {
655 m_pointList[m_pointList.size() - 1] = parent->
RotateAtPosition(m_pointList[m_pointList.size() - 1], rotAngle);
657 UpdateSwitchesPosition();
658 UpdatePowerFlowArrowsPosition();
663 m_pointList = pointList;
664 UpdateSwitchesPosition();
665 UpdatePowerFlowArrowsPosition();
677 wxString tipText = m_electricalData.name;
682 busNumber[0] =
static_cast<Bus*
>(m_parentList[0])->GetElectricalData().number + 1;
683 busNumber[1] =
static_cast<Bus*
>(m_parentList[1])->GetElectricalData().number + 1;
685 tipText += _(
"\nP") + wxString::Format(
"(%d-%d) = ", busNumber[0], busNumber[1]) +
686 wxString::FromDouble(m_electricalData.powerFlow[0].real(), 5) + _(
" p.u.");
687 tipText += _(
"\nQ") + wxString::Format(
"(%d-%d) = ", busNumber[0], busNumber[1]) +
688 wxString::FromDouble(m_electricalData.powerFlow[0].imag(), 5) + _(
" p.u.");
689 tipText += _(
"\nP") + wxString::Format(
"(%d-%d) = ", busNumber[1], busNumber[0]) +
690 wxString::FromDouble(m_electricalData.powerFlow[1].real(), 5) + _(
" p.u.");
691 tipText += _(
"\nQ") + wxString::Format(
"(%d-%d) = ", busNumber[1], busNumber[0]) +
692 wxString::FromDouble(m_electricalData.powerFlow[1].imag(), 5) + _(
" p.u.");
694 if (!m_electricalData.harmonicOrder.empty()) {
695 tipText += _(
"\n\nHarmonic currents:");
697 for (
auto& hCurrent1 : m_electricalData.harmonicCurrent[0]) {
698 auto& hCurrent2 = m_electricalData.harmonicCurrent[1][i];
700 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'));
701 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'));
715 double lineBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
716 double baseVoltage = GetValueFromUnit(data.nominalVoltage, data.nominalVoltageUnit);
717 double systemBaseImpedance = (baseVoltage * baseVoltage) / systemBasePower;
718 double lineBaseImpedance = (baseVoltage * baseVoltage) / lineBasePower;
721 double r = data.resistance;
724 if (data.useLinePower) data.resistance = (r * lineBaseImpedance) / systemBaseImpedance;
727 data.resistance = r / systemBaseImpedance;
732 double x = data.indReactance;
735 if (data.useLinePower) data.indReactance = (x * lineBaseImpedance) / systemBaseImpedance;
738 data.indReactance = x / systemBaseImpedance;
743 double b = data.capSusceptance;
746 if (data.useLinePower) data.capSusceptance = (b / lineBaseImpedance) * systemBaseImpedance;
749 data.capSusceptance = b * systemBaseImpedance;
756 double r0 = data.zeroResistance;
757 if (data.useLinePower) data.zeroResistance = (r0 * lineBaseImpedance) / systemBaseImpedance;
760 double x0 = data.zeroIndReactance;
761 if (data.useLinePower) data.zeroIndReactance = (x0 * lineBaseImpedance) / systemBaseImpedance;
764 double b0 = data.zeroCapSusceptance;
765 if (data.useLinePower) data.zeroCapSusceptance = (b0 / lineBaseImpedance) * systemBaseImpedance;
768 data.powerFlow[0] = std::complex<double>(0, 0);
769 data.powerFlow[1] = std::complex<double>(0, 0);
770 data.faultCurrent[0][0] = std::complex<double>(0, 0);
771 data.faultCurrent[0][1] = std::complex<double>(0, 0);
772 data.faultCurrent[0][2] = std::complex<double>(0, 0);
773 data.faultCurrent[1][0] = std::complex<double>(0, 0);
774 data.faultCurrent[1][1] = std::complex<double>(0, 0);
775 data.faultCurrent[1][2] = std::complex<double>(0, 0);
781rapidxml::xml_node<>* Line::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
783 auto elementNode = XMLParser::AppendNode(doc, elementListNode,
"Line");
784 XMLParser::SetNodeAttribute(doc, elementNode,
"ID", m_elementID);
785 auto cadProp = XMLParser::AppendNode(doc, elementNode,
"CADProperties");
786 auto nodeList = XMLParser::AppendNode(doc, cadProp,
"NodeList");
789 for (
unsigned int i = 0; i < m_pointList.size(); i++) {
792 if ((i != 1) && (i != m_pointList.size() - 2)) {
793 auto nodePos = XMLParser::AppendNode(doc, nodeList,
"Node");
794 XMLParser::SetNodeAttribute(doc, nodePos,
"ID", nodeID);
795 auto nodePosX = XMLParser::AppendNode(doc, nodePos,
"X");
796 XMLParser::SetNodeValue(doc, nodePosX, m_pointList[i].m_x);
797 auto nodePosY = XMLParser::AppendNode(doc, nodePos,
"Y");
798 XMLParser::SetNodeValue(doc, nodePosY, m_pointList[i].m_y);
803 auto parentIDList = XMLParser::AppendNode(doc, cadProp,
"ParentIDList");
804 for (
unsigned int i = 0; i < m_parentList.size(); i++) {
805 if (m_parentList[i]) {
806 auto parentID = XMLParser::AppendNode(doc, parentIDList,
"ParentID");
807 XMLParser::SetNodeAttribute(doc, parentID,
"ID",
static_cast<int>(i));
808 XMLParser::SetNodeValue(doc, parentID, m_parentList[i]->
GetID());
812 auto electricalProp = XMLParser::AppendNode(doc, elementNode,
"ElectricalProperties");
813 auto isOnline = XMLParser::AppendNode(doc, electricalProp,
"IsOnline");
814 XMLParser::SetNodeValue(doc, isOnline, m_online);
815 auto name = XMLParser::AppendNode(doc, electricalProp,
"Name");
816 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
817 auto nominalVoltage = XMLParser::AppendNode(doc, electricalProp,
"NominalVoltage");
818 XMLParser::SetNodeValue(doc, nominalVoltage, m_electricalData.nominalVoltage);
819 XMLParser::SetNodeAttribute(doc, nominalVoltage,
"UnitID",
static_cast<int>(m_electricalData.nominalVoltageUnit));
820 auto nominalPower = XMLParser::AppendNode(doc, electricalProp,
"NominalPower");
821 XMLParser::SetNodeValue(doc, nominalPower, m_electricalData.nominalPower);
822 XMLParser::SetNodeAttribute(doc, nominalPower,
"UnitID",
static_cast<int>(m_electricalData.nominalPowerUnit));
823 auto resistance = XMLParser::AppendNode(doc, electricalProp,
"Resistance");
824 XMLParser::SetNodeValue(doc, resistance, m_electricalData.resistance);
825 XMLParser::SetNodeAttribute(doc, resistance,
"UnitID",
static_cast<int>(m_electricalData.resistanceUnit));
826 auto indReactance = XMLParser::AppendNode(doc, electricalProp,
"IndReactance");
827 XMLParser::SetNodeValue(doc, indReactance, m_electricalData.indReactance);
828 XMLParser::SetNodeAttribute(doc, indReactance,
"UnitID",
static_cast<int>(m_electricalData.indReactanceUnit));
829 auto capSusceptance = XMLParser::AppendNode(doc, electricalProp,
"CapSusceptance");
830 XMLParser::SetNodeValue(doc, capSusceptance, m_electricalData.capSusceptance);
831 XMLParser::SetNodeAttribute(doc, capSusceptance,
"UnitID",
static_cast<int>(m_electricalData.capSusceptanceUnit));
832 auto lineSize = XMLParser::AppendNode(doc, electricalProp,
"LineSize");
833 XMLParser::SetNodeValue(doc, lineSize, m_electricalData.lineSize);
834 auto useLinePower = XMLParser::AppendNode(doc, electricalProp,
"UseLinePower");
835 XMLParser::SetNodeValue(doc, useLinePower, m_electricalData.useLinePower);
837 auto fault = XMLParser::AppendNode(doc, electricalProp,
"Fault");
838 auto zeroResistance = XMLParser::AppendNode(doc, fault,
"ZeroResistance");
839 XMLParser::SetNodeValue(doc, zeroResistance, m_electricalData.zeroResistance);
840 auto zeroIndReactance = XMLParser::AppendNode(doc, fault,
"ZeroIndReactance");
841 XMLParser::SetNodeValue(doc, zeroIndReactance, m_electricalData.zeroIndReactance);
842 auto zeroCapSusceptance = XMLParser::AppendNode(doc, fault,
"ZeroCapSusceptance");
843 XMLParser::SetNodeValue(doc, zeroCapSusceptance, m_electricalData.zeroCapSusceptance);
845 SaveSwitchingData(doc, electricalProp);
850bool Line::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
852 auto cadPropNode = elementNode->first_node(
"CADProperties");
853 if (!cadPropNode)
return false;
856 std::vector<wxPoint2DDouble> ptsList;
857 auto nodePosList = cadPropNode->first_node(
"NodeList");
858 if (!nodePosList)
return false;
859 auto nodePos = nodePosList->first_node(
"Node");
861 double nodePosX = XMLParser::GetNodeValueDouble(nodePos,
"X");
862 double nodePosY = XMLParser::GetNodeValueDouble(nodePos,
"Y");
863 ptsList.push_back(wxPoint2DDouble(nodePosX, nodePosY));
864 nodePos = nodePos->next_sibling(
"Node");
868 auto parentIDList = cadPropNode->first_node(
"ParentIDList");
869 if (!parentIDList)
return false;
870 auto parentNode = parentIDList->first_node(
"ParentID");
871 long parentID[2] = { -1, -1 };
874 wxString(parentNode->first_attribute(
"ID")->value()).ToCLong(&index);
875 wxString(parentNode->value()).ToCLong(&parentID[index]);
876 parentNode = parentNode->next_sibling(
"ParentID");
879 std::vector<wxPoint2DDouble> nodePtsList;
880 nodePtsList.push_back(ptsList[0]);
881 nodePtsList.push_back(ptsList[ptsList.size() - 1]);
884 std::vector<Bus*> dummyBusList;
885 for (
unsigned int i = 0; i < nodePtsList.size(); ++i) {
886 if (parentID[i] == -1)
888 Bus* dummyBus =
new Bus(nodePtsList[i]);
889 dummyBusList.push_back(dummyBus);
893 AddParent(parentList[parentID[i]], nodePtsList[i]);
898 std::vector<wxPoint2DDouble> midPts;
899 for (
unsigned int i = 1; i < ptsList.size() - 1; i++) midPts.push_back(ptsList[i]);
900 m_pointList.insert(m_pointList.begin() + 2, midPts.begin(), midPts.end());
904 for (
auto it = dummyBusList.begin(), itEnd = dummyBusList.end(); it != itEnd; ++it) {
908 dummyBusList.clear();
910 auto electricalProp = elementNode->first_node(
"ElectricalProperties");
911 if (!electricalProp)
return false;
913 SetOnline(XMLParser::GetNodeValueInt(electricalProp,
"IsOnline"));
914 m_electricalData.name = electricalProp->first_node(
"Name")->value();
915 m_electricalData.nominalVoltage = XMLParser::GetNodeValueDouble(electricalProp,
"NominalVoltage");
916 m_electricalData.nominalVoltageUnit =
917 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"NominalVoltage",
"UnitID"));
918 m_electricalData.nominalPower = XMLParser::GetNodeValueDouble(electricalProp,
"NominalPower");
919 m_electricalData.nominalPowerUnit =
920 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"NominalPower",
"UnitID"));
921 m_electricalData.resistance = XMLParser::GetNodeValueDouble(electricalProp,
"Resistance");
922 m_electricalData.resistanceUnit =
923 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"Resistance",
"UnitID"));
924 m_electricalData.indReactance = XMLParser::GetNodeValueDouble(electricalProp,
"IndReactance");
925 m_electricalData.indReactanceUnit =
926 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"IndReactance",
"UnitID"));
927 m_electricalData.capSusceptance = XMLParser::GetNodeValueDouble(electricalProp,
"CapSusceptance");
928 m_electricalData.capSusceptanceUnit =
929 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp,
"CapSusceptance",
"UnitID"));
930 m_electricalData.lineSize = XMLParser::GetNodeValueDouble(electricalProp,
"LineSize");
931 m_electricalData.useLinePower = XMLParser::GetNodeValueInt(electricalProp,
"UseLinePower");
933 auto fault = electricalProp->first_node(
"Fault");
934 m_electricalData.zeroResistance = XMLParser::GetNodeValueDouble(fault,
"ZeroResistance");
935 m_electricalData.zeroIndReactance = XMLParser::GetNodeValueDouble(fault,
"ZeroIndReactance");
936 m_electricalData.zeroCapSusceptance = XMLParser::GetNodeValueDouble(fault,
"ZeroCapSusceptance");
938 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