Power System Platform  2026w11a-beta
Loading...
Searching...
No Matches
Line.cpp
1/*
2 * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#include "Line.h"
19#include "../../utils/Path.h"
20
21Line::Line() : Branch()
22{
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); }
26 }
27}
28
29Line::Line(wxString name) : Branch()
30{
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); }
34 }
35 m_electricalData.name = name;
36}
37Line::~Line() {}
38bool Line::Contains(wxPoint2DDouble position) const
39{
40 if (PointToLineDistance(position) < 5.0) { return true; }
41 return false;
42}
43
44//void Line::Draw(wxPoint2DDouble translation, double scale) const
45//{
46// OpenGLColour elementColour;
47// if (m_online) {
48// if (m_dynEvent)
49// elementColour = m_dynamicEventColour;
50// else
51// elementColour = m_onlineElementColour;
52//
53// }
54// else
55// elementColour = m_offlineElementColour;
56//
57// std::vector<wxPoint2DDouble> pointList = m_pointList;
58// if (!m_inserted && pointList.size() > 0) {
59// wxPoint2DDouble secondPoint = m_position;
60// if (pointList.size() > 2) { secondPoint = pointList[2]; }
61// pointList[1] = GetSwitchPoint(m_parentList[0], pointList[0], secondPoint);
62// pointList.push_back(m_position);
63// }
64//
65// // Line selected (Layer 1).
66// if (m_selected) {
67// glLineWidth(1.5 + m_borderSize * 2.0);
68// glColor4dv(m_selectionColour.GetRGBA());
69// DrawLine(pointList);
70//
71// // Draw nodes selection.
72// if (pointList.size() > 0) {
73// DrawCircle(pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
74// if (m_inserted) { DrawCircle(pointList[pointList.size() - 1], 5.0 + m_borderSize / scale, 10, GL_POLYGON); }
75// }
76// }
77//
78// // Draw line (Layer 2)
79// glLineWidth(1.5);
80// glColor4dv(elementColour.GetRGBA());
81// DrawLine(pointList);
82//
83// if (m_inserted) {
84// DrawSwitches();
85// DrawPowerFlowPts();
86// }
87//
88// // Draw nodes.
89// if (pointList.size() > 0) {
90// glColor4dv(elementColour.GetRGBA());
91// DrawCircle(pointList[0], 5.0, 10, GL_POLYGON);
92// if (m_inserted) { DrawCircle(pointList[pointList.size() - 1], 5.0, 10, GL_POLYGON); }
93// }
94//
95// // Draw pickboxes (Layer 3).
96// if (m_showPickbox) {
97// glPushMatrix();
98// glLoadIdentity();
99//
100// for (int i = 2; i < (int)m_pointList.size() - 2; i++) {
101// DrawPickbox(WorldToScreen(m_pointList[i], translation, scale));
102// }
103//
104// glPopMatrix();
105// }
106//}
107
108void Line::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const
109{
110 //gc->SetBrush(*wxTRANSPARENT_BRUSH);
111
112 wxGraphicsMatrix identityMatrix = gc->GetTransform();
113 identityMatrix.Set(); // Set to identity
114
115 wxColour elementColour;
116 if (m_online) {
117 if (m_dynEvent)
118 elementColour = m_dynamicEventColour;
119 else
120 elementColour = m_onlineElementColour;
121
122 }
123 else
124 elementColour = m_offlineElementColour;
125
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);
132 }
133
134 // Line selected (Layer 1).
135 if (m_selected) {
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]);
140
141 // Draw nodes selection.
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); }
147 }
148 }
149
150 // Draw line (Layer 2)
151 gc->SetPen(wxPen(elementColour, 2));
152 gc->SetBrush(*wxTRANSPARENT_BRUSH);
153 if (pointList.size() > 0)
154 gc->StrokeLines(pointList.size(), &pointList[0]);
155
156 if (m_inserted) {
157 DrawDCSwitches(gc);
159 }
160
161 // Draw nodes.
162 gc->SetPen(*wxTRANSPARENT_PEN);
163 gc->SetBrush(wxBrush(elementColour));
164 if (pointList.size() > 0) {
165 DrawDCCircle(pointList[0], 5.0, 10, gc);
166 if (m_inserted) { DrawDCCircle(pointList[pointList.size() - 1], 5.0, 10, gc); }
167 }
168
169 // Draw pickboxes (Layer 3).
170 if (m_showPickbox) {
171 gc->PushState();
172 gc->SetTransform(identityMatrix);
173
174 for (int i = 2; i < (int)m_pointList.size() - 2; i++) {
175 DrawDCPickbox(WorldToScreen(m_pointList[i], translation - wxPoint2DDouble(4 / scale, 4 / scale), scale), gc);
176 }
177
178 gc->PopState();
179 }
180}
181
182void Line::DrawDC(wxPoint2DDouble translation, double scale, wxDC& dc) const
183{
184
185 wxColour elementColour;
186 if (m_online) {
187 if (m_dynEvent)
188 elementColour = m_dynamicEventColour;
189 else
190 elementColour = m_onlineElementColour;
191
192 }
193 else
194 elementColour = m_offlineElementColour;
195
196 std::vector<wxPoint> pointList;
197 for (auto pt : m_pointList) {
198 pointList.emplace_back(pt.m_x, pt.m_y);
199 }
200 //if (!m_inserted && pointList.size() > 0) {
201 // wxPoint secondPoint = wxPoint(m_position.m_x, m_position.m_y);
202 // if (pointList.size() > 2) { secondPoint = pointList[2]; }
203 // wxPoint2DDouble swPoint = GetSwitchPoint(m_parentList[0], pointList[0], secondPoint)
204 // pointList[1] = wxPoint(m_position.m_x, m_position.m_y);
205 // pointList.push_back(m_position);
206 //}
207
208 // Line selected (Layer 1).
209 if (m_selected) {
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]);
214
215 // Draw nodes selection.
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); }
221 }
222 }
223
224 // Draw line (Layer 2)
225 dc.SetPen(wxPen(elementColour, 2));
226 dc.SetBrush(*wxTRANSPARENT_BRUSH);
227 if (pointList.size() > 0)
228 dc.DrawLines(pointList.size(), &pointList[0]);
229
230 if (m_inserted) {
231 DrawDCSwitches(dc);
233 }
234
235 // Draw nodes.
236 dc.SetPen(*wxTRANSPARENT_PEN);
237 dc.SetBrush(wxBrush(elementColour));
238 if (pointList.size() > 0) {
239 DrawDCCircle(pointList[0], 5.0, dc);
240 if (m_inserted) { DrawDCCircle(pointList[pointList.size() - 1], 5.0, dc); }
241 }
242
243 // Draw pickboxes (Layer 3).
244 //if (m_showPickbox) {
245 // gc->PushState();
246 // gc->SetTransform(identityMatrix);
247 //
248 // for (int i = 2; i < (int)m_pointList.size() - 2; i++) {
249 // DrawDCPickbox(WorldToScreen(m_pointList[i], translation - wxPoint2DDouble(4 / scale, 4 / scale), scale), gc);
250 // }
251 //
252 // gc->PopState();
253 //}
254}
255
256void Line::Move(wxPoint2DDouble position)
257{
258 if (!m_parentList[0]) {
259 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
260 UpdateSwitchesPosition();
261 UpdatePowerFlowArrowsPosition();
262 }
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();
267 }
268
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;
272 }
273 }
274}
275
276bool Line::AddParent(Element* parent, wxPoint2DDouble position)
277{
278 if (parent) {
279 // First bus.
280 if (m_parentList.size() == 0) {
281 m_position = position;
282 m_parentList.push_back(parent);
283 parent->AddChild(this);
284 wxPoint2DDouble parentPt =
285 parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
286 parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
287 parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
288 m_pointList.push_back(parentPt); // First point
289 m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
290
291 wxRect2DDouble genRect(0, 0, 0, 0);
292 m_switchRect.push_back(genRect);
294
295 Bus* parentBus = static_cast<Bus*>(parent);
296 m_electricalData.nominalVoltage = parentBus->GetElectricalData().nominalVoltage;
297 m_electricalData.nominalVoltageUnit = parentBus->GetElectricalData().nominalVoltageUnit;
298
299 return false;
300 }
301 // Second bus.
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();
311 return false;
312 }
313
314 m_parentList.push_back(parent);
315 parent->AddChild(this);
316 wxPoint2DDouble parentPt =
317 parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
318 parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
319 parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
320
321 // Set first switch point.
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);
325
326 // Set the second switch point.
327 m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_pointList[m_pointList.size() - 1]));
328
329 m_pointList.push_back(parentPt); // Last point.
330
331 wxRect2DDouble genRect(0, 0, 0, 0);
332 m_switchRect.push_back(genRect);
334
335 SetInserted();
336 UpdatePowerFlowArrowsPosition();
337 return true;
338 }
339 }
340 return false;
341}
342bool Line::Intersects(wxRect2DDouble rect) const
343{
344 for (auto it = m_pointList.begin(); it != m_pointList.end(); ++it) {
345 if (rect.Contains(*it)) return true;
346 }
347 return false;
348}
349void Line::MovePickbox(wxPoint2DDouble position)
350{
351 if (m_activePickboxID == ID_PB_NONE) return;
352
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();
358 }
359 }
360}
361bool Line::PickboxContains(wxPoint2DDouble position)
362{
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;
367 return true;
368 }
369 }
370 return false;
371}
372
373void Line::AddPoint(wxPoint2DDouble point)
374{
375 if (m_parentList.size() != 0) { m_pointList.push_back(point); }
376}
377
378void Line::StartMove(wxPoint2DDouble position)
379{
380 m_moveStartPt = position;
381 m_movePts = m_pointList;
382}
383
384void Line::MoveNode(Element* parent, wxPoint2DDouble position)
385{
386 if (parent) {
387 // First bus.
388 if (parent == m_parentList[0]) {
389 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
390 }
391 // Second bus.
392 else if (parent == m_parentList[1]) {
393 m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
394 }
395
396 // If the line is selected, move all the points, except the switches and buses points.
397 if (m_selected) {
398 for (int i = 2; i < (int)m_pointList.size() - 1; i++) {
399 m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
400 }
401 }
402 }
403 else {
404 // If parent is setted to nullptr for the firts time, remove the parent child
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;
410 m_online = false;
411 }
412 }
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;
418 m_online = false;
419 }
420 }
421 }
422
423 // Recalculate switches positions
424 UpdateSwitchesPosition();
425 UpdatePowerFlowArrowsPosition();
426}
427
428bool Line::GetContextMenu(wxMenu& menu)
429{
430 //wxFileName exeFileName(wxStandardPaths::Get().GetExecutablePath());
431 //wxString exePath = exeFileName.GetPath();
432
433 menu.Append(ID_EDIT_ELEMENT, _("Edit line"));
434
435 wxString busName[2] = { "?", "?" };
436 if (m_parentList.size() == 2) {
437 int i = 0;
438 for (Element* element : m_parentList) {
439 if (element) {
440 Bus* bus = static_cast<Bus*>(element);
441 busName[i] = bus->GetElectricalData().name;
442 }
443 i++;
444 }
445 }
446
447 wxMenu* textMenu = new wxMenu();
448
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"));
461
462 if (m_activePickboxID == ID_PB_NONE) {
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);
466 }
467 else {
468 wxMenuItem* addNodeItem = new wxMenuItem(&menu, ID_LINE_REMOVE_NODE, _("Remove node"));
469 addNodeItem->SetBitmap(wxImage(Paths::GetDataPath() + "/images/menu/removeNode16.png"));
470 menu.Append(addNodeItem);
471 }
472 wxMenuItem* deleteItem = new wxMenuItem(&menu, ID_DELETE, _("Delete"));
473 deleteItem->SetBitmap(wxImage(Paths::GetDataPath() + "/images/menu/delete16.png"));
474 menu.Append(deleteItem);
475 return true;
476}
477
478void Line::RemoveNode(wxPoint2DDouble point)
479{
480 if (PickboxContains(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);
484 break;
485 }
486 }
487 }
488 UpdateSwitchesPosition();
489 UpdatePowerFlowArrowsPosition();
490}
491
492void Line::AddNode(wxPoint2DDouble point)
493{
494 int segmentNumber = 0;
495 PointToLineDistance(point, &segmentNumber);
496 if (segmentNumber > 0 && segmentNumber < (int)m_pointList.size() - 2) {
497 m_pointList.insert(m_pointList.begin() + segmentNumber + 1, point);
498 }
499 UpdateSwitchesPosition();
500 UpdatePowerFlowArrowsPosition();
501}
502
503void Line::CalculateBoundaries(wxPoint2DDouble& leftUp, wxPoint2DDouble& rightBottom) const
504{
505 if (m_pointList.size() > 0) {
506 // Check points list boundaries.
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;
514 }
515 }
516}
517
518bool Line::ShowForm(wxWindow* parent, Element* element, wxWindow* workspace)
519{
520 LineForm lineForm(parent, this);
521 lineForm.CenterOnParent();
522 if (lineForm.ShowModal() == wxID_OK) {
523 return true;
524 }
525 return false;
526}
527
528void Line::SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit)
529{
530 if (nominalVoltage.size() > 0) {
531 m_electricalData.nominalVoltage = nominalVoltage[0];
532 m_electricalData.nominalVoltageUnit = nominalVoltageUnit[0];
533 }
534}
535
537{
538 if (m_activeNodeID == 1 && parent == m_parentList[0]) return false;
539 if (m_activeNodeID == 2 && parent == m_parentList[1]) return false;
540
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);
546 }
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);
551 }
552
553 if (parent->Intersects(nodeRect)) {
554 // If the line has no parents set the new rated voltage, otherwise check if it's not connecting
555 // two different voltages buses
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;
560 }
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();
568 m_activeNodeID = 0;
569 return false;
570 }
571
572 if (m_activeNodeID == 1) {
573 // Check if the user is trying to connect the same bus.
574 if (m_parentList[1] == parent) {
575 m_activeNodeID = 0;
576 return false;
577 }
578
579 m_parentList[0] = parent;
580
581 // Centralize the node on bus.
582 wxPoint2DDouble parentPt = parent->RotateAtPosition(
583 m_pointList[0], -parent->GetAngle()); // Rotate click to horizontal position.
584 parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
585 parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
586 m_pointList[0] = parentPt;
587
588 UpdateSwitchesPosition();
589 UpdatePowerFlowArrowsPosition();
590 return true;
591 }
592 if (m_activeNodeID == 2) {
593 if (m_parentList[0] == parent) {
594 m_activeNodeID = 0;
595 return false;
596 }
597
598 m_parentList[1] = parent;
599
600 wxPoint2DDouble parentPt =
601 parent->RotateAtPosition(m_pointList[m_pointList.size() - 1], -parent->GetAngle());
602 parentPt.m_y = parent->GetPosition().m_y;
603 parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
604 m_pointList[m_pointList.size() - 1] = parentPt;
605
606 UpdateSwitchesPosition();
607 UpdatePowerFlowArrowsPosition();
608 return true;
609 }
610 }
611 else {
612 if (m_activeNodeID == 1) m_parentList[0] = nullptr;
613 if (m_activeNodeID == 2) m_parentList[1] = nullptr;
614 }
615 }
616 return false;
617}
618
620{
621 m_pfDirection = pfDirection;
622 UpdatePowerFlowArrowsPosition();
623}
624
625void Line::UpdatePowerFlowArrowsPosition()
626{
627 std::vector<wxPoint2DDouble> edges;
628 switch (m_pfDirection) {
630 m_powerFlowArrow.clear();
631 } break;
633 for (int i = 1; i < (int)m_pointList.size() - 1; i++) { edges.push_back(m_pointList[i]); }
634 } break;
636 for (int i = (int)m_pointList.size() - 2; i > 0; i--) { edges.push_back(m_pointList[i]); }
637 } break;
638 default:
639 break;
640 }
642}
643
644void Line::RotateNode(Element* parent, bool clockwise)
645{
646 double rotAngle = m_rotationAngle;
647 if (!clockwise) rotAngle = -m_rotationAngle;
648
649 if (parent == m_parentList[0]) {
650 m_pointList[0] = parent->RotateAtPosition(m_pointList[0], rotAngle);
651 }
652 else if (parent == m_parentList[1]) {
653 m_pointList[m_pointList.size() - 1] = parent->RotateAtPosition(m_pointList[m_pointList.size() - 1], rotAngle);
654 }
655 UpdateSwitchesPosition();
656 UpdatePowerFlowArrowsPosition();
657}
658
659void Line::SetPointList(std::vector<wxPoint2DDouble> pointList)
660{
661 m_pointList = pointList;
662 UpdateSwitchesPosition();
663 UpdatePowerFlowArrowsPosition();
664}
665
667{
668 Line* copy = new Line();
669 *copy = *this;
670 return copy;
671}
672
673wxString Line::GetTipText() const
674{
675 wxString tipText = m_electricalData.name;
676
677 if (m_online) {
678 tipText += "\n";
679 int busNumber[2];
680 busNumber[0] = static_cast<Bus*>(m_parentList[0])->GetElectricalData().number + 1;
681 busNumber[1] = static_cast<Bus*>(m_parentList[1])->GetElectricalData().number + 1;
682
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.");
691
692 if (!m_electricalData.harmonicOrder.empty()) {
693 tipText += _("\n\nHarmonic currents:");
694 int i = 0;
695 for (auto& hCurrent1 : m_electricalData.harmonicCurrent[0]) {
696 auto& hCurrent2 = m_electricalData.harmonicCurrent[1][i];
697 wxString i1, i2;
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'));
700
701 tipText += i1 + i2;
702 i++;
703 }
704 }
705 }
706
707 return tipText;
708}
709
710LineElectricalData Line::GetPUElectricalData(double systemBasePower)
711{
713
714 data.nominalPower = m_electricalData.nominalPower;
715 data.nominalPowerUnit = m_electricalData.nominalPowerUnit;
716
717 data.nominalVoltage = m_electricalData.nominalVoltage;
718 data.nominalVoltageUnit = m_electricalData.nominalVoltageUnit;
719
720 data.useLinePower = m_electricalData.useLinePower;
721
722 data.lineSize = m_electricalData.lineSize;
723
724 data.resistance = m_electricalData.resistance;
725 data.resistanceUnit = m_electricalData.resistanceUnit;
726
727 data.indReactance = m_electricalData.indReactance;
728 data.indReactanceUnit = m_electricalData.indReactanceUnit;
729
730 data.capSusceptance = m_electricalData.capSusceptance;
731 data.capSusceptanceUnit = m_electricalData.capSusceptanceUnit;
732
733 data.zeroResistance = m_electricalData.zeroResistance;
734 data.zeroIndReactance = m_electricalData.zeroIndReactance;
735 data.zeroCapSusceptance = m_electricalData.zeroCapSusceptance;
736
737 data.powerFlow[0] = m_electricalData.powerFlow[0];
738 data.powerFlow[1] = m_electricalData.powerFlow[1];
739
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;
744
745 // Resistance
746 double r = data.resistance;
747 if (data.resistanceUnit == ElectricalUnit::UNIT_OHM_km) data.resistance = r * data.lineSize / systemBaseImpedance;
748 else if (data.resistanceUnit == ElectricalUnit::UNIT_PU) {
749 if (data.useLinePower) data.resistance = (r * lineBaseImpedance) / systemBaseImpedance;
750 }
751 else { // Ohm
752 data.resistance = r / systemBaseImpedance;
753 }
754 data.resistanceUnit = ElectricalUnit::UNIT_PU;
755
756 // Inductive reactance
757 double x = data.indReactance;
758 if (data.indReactanceUnit == ElectricalUnit::UNIT_OHM_km) data.indReactance = x * data.lineSize / systemBaseImpedance;
759 else if (data.indReactanceUnit == ElectricalUnit::UNIT_PU) {
760 if (data.useLinePower) data.indReactance = (x * lineBaseImpedance) / systemBaseImpedance;
761 }
762 else { // Ohm
763 data.indReactance = x / systemBaseImpedance;
764 }
765 data.indReactanceUnit = ElectricalUnit::UNIT_PU;
766
767 // Capacitive susceptance
768 double b = data.capSusceptance;
769 if (data.capSusceptanceUnit == ElectricalUnit::UNIT_S_km) data.capSusceptance = b * data.lineSize * systemBaseImpedance;
770 else if (data.capSusceptanceUnit == ElectricalUnit::UNIT_PU) {
771 if (data.useLinePower) data.capSusceptance = (b / lineBaseImpedance) * systemBaseImpedance;
772 }
773 else { // S
774 data.capSusceptance = b * systemBaseImpedance;
775 }
776 data.capSusceptanceUnit = ElectricalUnit::UNIT_PU;
777
778 // Fault
779
780 // Zero seq. resistance
781 double r0 = data.zeroResistance;
782 if (data.useLinePower) data.zeroResistance = (r0 * lineBaseImpedance) / systemBaseImpedance;
783
784 // Zero seq. ind. reactance
785 double x0 = data.zeroIndReactance;
786 if (data.useLinePower) data.zeroIndReactance = (x0 * lineBaseImpedance) / systemBaseImpedance;
787
788 // Zero seq. cap. susceptance
789 double b0 = data.zeroCapSusceptance;
790 if (data.useLinePower) data.zeroCapSusceptance = (b0 / lineBaseImpedance) * systemBaseImpedance;
791
792 if (!m_online) {
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);
801 }
802
803 return data;
804}
805
806rapidxml::xml_node<>* Line::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
807{
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");
812 int nodeID = 0;
813 // Parse all the points.
814 for (unsigned int i = 0; i < m_pointList.size(); i++) {
815 // Don't save switch points, the method UpdateSwitchesPosition() calculate these points properly after open the
816 // element
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);
824 nodeID++;
825 }
826 }
827
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());
834 }
835 }
836
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);
861
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);
869
870 SaveSwitchingData(doc, electricalProp);
871
872 return elementNode;
873}
874
875bool Line::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
876{
877 auto cadPropNode = elementNode->first_node("CADProperties");
878 if (!cadPropNode) return false;
879
880 // Get nodes points
881 std::vector<wxPoint2DDouble> ptsList;
882 auto nodePosList = cadPropNode->first_node("NodeList");
883 if (!nodePosList) return false;
884 auto nodePos = nodePosList->first_node("Node");
885 while (nodePos) {
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");
890 }
891
892 // Get parents IDs
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 };
897 while (parentNode) {
898 long index = 0;
899 wxString(parentNode->first_attribute("ID")->value()).ToCLong(&index);
900 wxString(parentNode->value()).ToCLong(&parentID[index]);
901 parentNode = parentNode->next_sibling("ParentID");
902 }
903
904 std::vector<wxPoint2DDouble> nodePtsList; // List of node points
905 nodePtsList.push_back(ptsList[0]); // First point on the list
906 nodePtsList.push_back(ptsList[ptsList.size() - 1]); // Last point on the list
907
908 // List of dummy buses to set not connected nodes properly
909 std::vector<Bus*> dummyBusList;
910 for (unsigned int i = 0; i < nodePtsList.size(); ++i) {
911 if (parentID[i] == -1) // No parent connected
912 {
913 Bus* dummyBus = new Bus(nodePtsList[i]);
914 dummyBusList.push_back(dummyBus);
915 AddParent(dummyBus, nodePtsList[i]);
916 }
917 else { // Parent connected (necessarily a bus, get from bus list)
918 AddParent(parentList[parentID[i]], nodePtsList[i]);
919 }
920 }
921
922 // Add the others nodes (if exists)
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());
926 SetPointList(m_pointList);
927
928 // Remove dummy buses
929 for (auto it = dummyBusList.begin(), itEnd = dummyBusList.end(); it != itEnd; ++it) {
930 RemoveParent(*it);
931 delete* it;
932 }
933 dummyBusList.clear();
934
935 auto electricalProp = elementNode->first_node("ElectricalProperties");
936 if (!electricalProp) return false;
937
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");
957
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");
962
963 if (!OpenSwitchingData(electricalProp)) return false;
964 if (m_swData.swTime.size() != 0) SetDynamicEvent(true);
965 return true;
966}
@ ID_LINE_REMOVE_NODE
Definition Element.h:77
@ ID_DELETE
Definition Element.h:80
@ ID_EDIT_ELEMENT
Definition Element.h:75
@ ID_LINE_ADD_NODE
Definition Element.h:76
@ ID_PB_NONE
Definition Element.h:61
ElectricalUnit
Electrical units.
PowerFlowDirection
Direction of power flow arrows.
Abstract class for branch power elements.
Definition Branch.h:32
virtual void UpdateSwitches()
Update the switch position.
Definition Branch.cpp:179
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition Branch.cpp:105
Node for power elements. All others power elements are connected through this.
Definition Bus.h:86
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition Element.h:112
virtual bool Intersects(wxRect2DDouble rect) const =0
Check if the element's rect intersects other rect.
virtual int GetID() const
Get the element ID.
Definition Element.h:271
virtual double PointToLineDistance(wxPoint2DDouble point, int *segmentNumber=nullptr) const
Calculate the distance between a line (formed by point list) and a point.
Definition Element.cpp:529
wxPoint2DDouble GetPosition() const
Get the element position.
Definition Element.h:186
double GetAngle() const
Get the element angle.
Definition Element.h:211
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
Definition Element.cpp:223
virtual void DrawDCPickbox(wxPoint2DDouble position, wxGraphicsContext *gc) const
Draw a point.
Definition Element.cpp:216
virtual wxPoint2DDouble WorldToScreen(wxPoint2DDouble translation, double scale, double offsetX=0.0, double offsetY=0.0) const
Convert the element position to screen position.
Definition Element.cpp:267
virtual void AddChild(Element *child)
Add a child to the child list.
Definition Element.cpp:494
bool SetOnline(bool online=true)
Set if the element is online or offline.
Definition Element.cpp:378
virtual void DrawDCCircle(wxPoint2DDouble position, double radius, int numSegments, wxGraphicsContext *gc) const
Draw a circle using device context.
Definition Element.cpp:168
void SetInserted(bool inserted=true)
Set if the element is properly inserted in the workspace.
Definition Element.h:631
Form to edit the line power data.
Definition LineForm.h:33
Power line element.
Definition Line.h:64
virtual void AddPoint(wxPoint2DDouble point)
Add point to the list of points that connect the element to the bus.
Definition Line.cpp:373
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition Line.cpp:38
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element's rect intersects other rect.
Definition Line.cpp:342
virtual void SetNominalVoltage(std::vector< double > nominalVoltage, std::vector< ElectricalUnit > nominalVoltageUnit)
Set nominal voltage of the element.
Definition Line.cpp:528
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,...
Definition Line.cpp:276
virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
Definition Line.cpp:108
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition Line.cpp:256
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
Definition Line.cpp:619
virtual wxString GetTipText() const
Get the tip text.
Definition Line.cpp:673
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...
Definition Line.cpp:536
virtual bool ShowForm(wxWindow *parent, Element *element, wxWindow *workspace=nullptr)
Show element data form.
Definition Line.cpp:518
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition Line.cpp:428
virtual void CalculateBoundaries(wxPoint2DDouble &leftUp, wxPoint2DDouble &rightBottom) const
Calculate the element boundaries.
Definition Line.cpp:503
virtual void RotateNode(Element *parent, bool clockwise=true)
Rotate a node.
Definition Line.cpp:644
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition Line.cpp:378
virtual void MoveNode(Element *parent, wxPoint2DDouble position)
Move a node. StartMove(wxPoint2DDouble position) before start moving.
Definition Line.cpp:384
virtual bool PickboxContains(wxPoint2DDouble position)
Check if a pickbox contains a point. If contains the attributes related to pickbox movement will be c...
Definition Line.cpp:361
virtual void SetPointList(std::vector< wxPoint2DDouble > pointList)
Set the list of points that connect the element to the bus.
Definition Line.cpp:659
virtual void MovePickbox(wxPoint2DDouble position)
Move the pickbox.
Definition Line.cpp:349
virtual Element * GetCopy()
Get a the element copy.
Definition Line.cpp:666
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