Power System Platform  2026w34a-beta
Loading...
Searching...
No Matches
Load.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 "Load.h"
19#include <wx/log.h>
20
21Load::Load() : Shunt()
22{
23 m_elementType = TYPE_LOAD;
24}
25
26Load::Load(wxString name) : Shunt()
27{
28 m_elementType = TYPE_LOAD;
29 m_electricalData.name = name;
30}
31
32Load::~Load() {}
33
34bool Load::AddParent(Element* parent, wxPoint2DDouble position, bool isOpening)
35{
36 if (parent) {
37 m_parentList.push_back(parent);
38 parent->AddChild(this);
39 wxPoint2DDouble parentPt =
40 parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
41 parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
42 parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
43
44 m_position = parentPt + wxPoint2DDouble(0.0, 100.0); // Shifts the position to the down of the bus.
45 m_width = m_height = 20.0;
46 m_rect = wxRect2DDouble(m_position.m_x - 10.0, m_position.m_y - 10.0, m_width, m_height);
47
48 m_pointList.push_back(parentPt);
49 m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
50 m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -20.0));
51 m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -10.0));
52
53 m_triangPts.push_back(wxPoint2DDouble(-m_width / 2.0, -m_height / 2.0));
54 m_triangPts.push_back(wxPoint2DDouble(m_width / 2.0, -m_height / 2.0));
55 m_triangPts.push_back(wxPoint2DDouble(0.0, m_height / 2.0));
56
57 m_inserted = true;
58
59 wxRect2DDouble genRect(0, 0, 0, 0);
60 m_switchRect.push_back(genRect); // Push a general rectangle.
63 UpdatePowerFlowArrowsPosition();
64
65 return true;
66 }
67 return false;
68}
69
70void Load::DrawDC(GUIColour* guiColour, wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const
71{
72 wxColour elementColour;
73 if (m_online) {
74 //if (m_dynEvent)
75 // elementColour = guiColour->eventElement;
76 //else
77 elementColour = guiColour->enabled;
78 }
79 else
80 elementColour = guiColour->disable;
81
82 if (m_inserted) {
83 // Draw Selection (layer 1).
84 if (m_selected) {
85 gc->SetPen(wxPen(guiColour->selection, 2 + m_borderSize * 2.0));
86 gc->SetBrush(*wxTRANSPARENT_BRUSH);
87
88 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
89
90 gc->SetPen(*wxTRANSPARENT_PEN);
91 gc->SetBrush(wxBrush(guiColour->selection));
92
93 std::vector<wxPoint2DDouble> selTriangPts;
94 selTriangPts.push_back(m_triangPts[0] + m_position +
95 wxPoint2DDouble(-m_borderSize / scale, -m_borderSize / scale));
96 selTriangPts.push_back(m_triangPts[1] + m_position +
97 wxPoint2DDouble(m_borderSize / scale, -m_borderSize / scale));
98 selTriangPts.push_back(m_triangPts[2] + m_position + wxPoint2DDouble(0.0, m_borderSize / scale));
99
100 // Push the current matrix on stack.
101 gc->PushState();
102 // Rotate the matrix around the object position.
103 gc->Translate(m_position.m_x, m_position.m_y);
104 gc->Rotate(wxDegToRad(m_angle));
105 gc->Translate(-m_position.m_x, -m_position.m_y);
106 DrawDCTriangle(selTriangPts, gc);
107 gc->PopState();
108
109 // Draw node selection.
110 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc);
111 }
112
113 // Draw Load (layer 2).
114 gc->SetPen(wxPen(elementColour, 2));
115 gc->SetBrush(*wxTRANSPARENT_BRUSH);
116 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
117
118 // Draw node.
119 gc->SetPen(*wxTRANSPARENT_PEN);
120 gc->SetBrush(wxBrush(elementColour));
121 DrawDCCircle(m_pointList[0], 5.0, 10, gc);
122
123 DrawDCSwitches(guiColour, gc);
124 DrawDCPowerFlowPts(guiColour, gc);
125
126 std::vector<wxPoint2DDouble> triangPts;
127 for (int i = 0; i < 3; i++) { triangPts.push_back(m_triangPts[i] + m_position); }
128 gc->PushState();
129 gc->Translate(m_position.m_x, m_position.m_y);
130 gc->Rotate(wxDegToRad(m_angle));
131 gc->Translate(-m_position.m_x, -m_position.m_y);
132 gc->SetPen(*wxTRANSPARENT_PEN);
133 gc->SetBrush(wxBrush(elementColour));
134 DrawDCTriangle(triangPts, gc);
135 gc->PopState();
136
137 if (m_dynEvent) {
138 DrawStabilityEventGC(gc, translation, scale, guiColour);
139 }
140 }
141}
142
143void Load::DrawDC(GUIColour* guiColour, wxPoint2DDouble translation, double scale, wxDC& dc) const
144{
145 wxColour elementColour;
146 if (m_online) {
147 if (m_dynEvent)
148 elementColour = guiColour->eventElement;
149 else
150 elementColour = guiColour->enabled;
151 }
152 else
153 elementColour = guiColour->disable;
154
155 std::vector<wxPoint> pointListInt;
156 for (auto& pt : m_pointList) {
157 pointListInt.emplace_back(static_cast<int>(pt.m_x), static_cast<int>(pt.m_y));
158 }
159 wxPoint pos = wxPoint(static_cast<int>(m_position.m_x), static_cast<int>(m_position.m_y));
160
161 if (m_inserted) {
162 // Draw Selection (layer 1).
163 if (m_selected) {
164 dc.SetPen(wxPen(guiColour->selection, 2 + m_borderSize * 2.0));
165 dc.SetBrush(*wxTRANSPARENT_BRUSH);
166
167 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
168
169 dc.SetPen(*wxTRANSPARENT_PEN);
170 dc.SetBrush(wxBrush(guiColour->selection));
171
172 wxPoint2DDouble p;
173 wxPoint selTriangPts[3];
174 p = m_triangPts[0] + m_position + wxPoint2DDouble(-m_borderSize / scale, -m_borderSize / scale);
175 selTriangPts[0] = RotateAround(p, m_position, m_angle);
176 p = m_triangPts[1] + m_position + wxPoint2DDouble(m_borderSize / scale, -m_borderSize / scale);
177 selTriangPts[1] = RotateAround(p, m_position, m_angle);
178 p = m_triangPts[2] + m_position + wxPoint2DDouble(0.0, m_borderSize / scale);
179 selTriangPts[2] = RotateAround(p, m_position, m_angle);
180
181 dc.DrawPolygon(3, selTriangPts);
182
183 // Draw node selection.
184 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, dc);
185 }
186
187 // Draw Load (layer 2).
188 dc.SetPen(wxPen(elementColour, 2));
189 dc.SetBrush(*wxTRANSPARENT_BRUSH);
190 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
191
192 // Draw node.
193 dc.SetPen(*wxTRANSPARENT_PEN);
194 dc.SetBrush(wxBrush(elementColour));
195 DrawDCCircle(m_pointList[0], 5.0, dc);
196
197 DrawDCSwitches(guiColour, dc);
198 DrawDCPowerFlowPts(guiColour, dc);
199
200 wxPoint2DDouble p;
201 wxPoint triangPts[3];
202
203 //std::vector<wxPoint2DDouble> triangPts;
204 for (int i = 0; i < 3; i++) {
205 p = m_triangPts[i] + m_position;
206 triangPts[i] = RotateAround(p, m_position, m_angle);
207 }
208 dc.SetPen(*wxTRANSPARENT_PEN);
209 dc.SetBrush(wxBrush(elementColour));
210 dc.DrawPolygon(3, triangPts);
211 }
212}
213
214void Load::Rotate(bool clockwise)
215{
216 double rotAngle = m_rotationAngle;
217 if (!clockwise) rotAngle = -m_rotationAngle;
218
219 m_angle += rotAngle;
220 if (m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
221 m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
222 m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
223 UpdateSwitchesPosition();
224 UpdatePowerFlowArrowsPosition();
225}
226
227bool Load::GetContextMenu(wxMenu& menu)
228{
229 menu.Append(ID_EDIT_ELEMENT, _("Edit Load"));
230
231 wxMenu* textMenu = new wxMenu();
232
233 textMenu->Append(ID_TXT_NAME, _("Name"));
234 textMenu->Append(ID_TXT_ACTIVE_POWER, _("Active power"));
235 textMenu->Append(ID_TXT_REACTIVE_POWER, _("Reactive power"));
236 textMenu->SetClientData(menu.GetClientData());
237
238
239 menu.AppendSubMenu(textMenu, _("Add text"));
240
241 GeneralMenuItens(menu);
242 return true;
243}
244
245bool Load::ShowForm(wxWindow* parent, Element* element, wxWindow* workspace)
246{
247 wxLogDebug("Before form constructor");
248 LoadForm loadForm(parent, this);
249 loadForm.CenterOnParent();
250 wxLogDebug("Before ShowModal");
251 if (loadForm.ShowModal() == wxID_OK) {
252 wxLogDebug("After ShowModal");
253 return true;
254 }
255 return false;
256}
257
258LoadElectricalData Load::GetPUElectricalData(double systemPowerBase)
259{
261
262 data.name = m_electricalData.name;
263
264 data.activePower = m_electricalData.activePower;
265 data.activePowerUnit = m_electricalData.activePowerUnit;
266
267 data.reactivePower = m_electricalData.reactivePower;
268 data.reactivePowerUnit = m_electricalData.reactivePowerUnit;
269
270 switch (data.activePowerUnit) {
271 case ElectricalUnit::UNIT_W: {
272 data.activePower = data.activePower / systemPowerBase;
273 data.activePowerUnit = ElectricalUnit::UNIT_PU;
274 } break;
275 case ElectricalUnit::UNIT_kW: {
276 data.activePower = (data.activePower * 1e3) / systemPowerBase;
277 data.activePowerUnit = ElectricalUnit::UNIT_PU;
278 } break;
279 case ElectricalUnit::UNIT_MW: {
280 data.activePower = (data.activePower * 1e6) / systemPowerBase;
281 data.activePowerUnit = ElectricalUnit::UNIT_PU;
282 } break;
283 default:
284 break;
285 }
286 switch (data.reactivePowerUnit) {
287 case ElectricalUnit::UNIT_var: {
288 data.reactivePower = data.reactivePower / systemPowerBase;
289 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
290 } break;
291 case ElectricalUnit::UNIT_kvar: {
292 data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
293 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
294 } break;
295 case ElectricalUnit::UNIT_Mvar: {
296 data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
297 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
298 } break;
299 default:
300 break;
301 }
302
303 return data;
304}
305
307{
308 Load* copy = new Load();
309 *copy = *this;
310 return copy;
311}
312
313wxString Load::GetTipText() const
314{
315 wxString tipText = m_electricalData.name;
316
317 // TODO: Avoid power calculation.
318 double activePower = m_electricalData.activePower;
319 double reactivePower = m_electricalData.reactivePower;
320 if (!m_online) {
321 activePower = 0.0;
322 reactivePower = 0.0;
323 }
324 if (m_online && m_electricalData.loadType == CONST_IMPEDANCE) {
325 std::complex<double> v = static_cast<Bus*>(m_parentList[0])->GetElectricalData().voltage;
326 reactivePower *= std::pow(std::abs(v), 2);
327 activePower *= std::pow(std::abs(v), 2);
328 }
329 tipText += "\n";
330 tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
331 switch (m_electricalData.activePowerUnit) {
332 case ElectricalUnit::UNIT_PU: {
333 tipText += _(" p.u.");
334 } break;
335 case ElectricalUnit::UNIT_W: {
336 tipText += _(" W");
337 } break;
338 case ElectricalUnit::UNIT_kW: {
339 tipText += _(" kW");
340 } break;
341 case ElectricalUnit::UNIT_MW: {
342 tipText += _(" MW");
343 } break;
344 default:
345 break;
346 }
347 tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
348 switch (m_electricalData.reactivePowerUnit) {
349 case ElectricalUnit::UNIT_PU: {
350 tipText += _(" p.u.");
351 } break;
352 case ElectricalUnit::UNIT_var: {
353 tipText += _(" var");
354 } break;
355 case ElectricalUnit::UNIT_kvar: {
356 tipText += _(" kvar");
357 } break;
358 case ElectricalUnit::UNIT_Mvar: {
359 tipText += _(" Mvar");
360 } break;
361 default:
362 break;
363 }
364
365 return tipText;
366}
367
369{
370 if (!m_electricalData.plotLoad) return false;
371 plotData.SetName(m_electricalData.name);
372 plotData.SetCurveType(ElementPlotData::CurveType::CT_LOAD);
373
374 std::vector<double> absVoltage, activePower, reactivePower, current;
375 for (unsigned int i = 0; i < m_electricalData.voltageVector.size(); ++i) {
376 absVoltage.push_back(std::abs(m_electricalData.voltageVector[i]));
377 activePower.push_back(std::real(m_electricalData.electricalPowerVector[i]));
378 reactivePower.push_back(std::imag(m_electricalData.electricalPowerVector[i]));
379 current.push_back(std::abs(std::complex<double>(activePower[i], -reactivePower[i]) /
380 std::conj(m_electricalData.voltageVector[i])));
381 }
382
383 plotData.AddData(absVoltage, _("Voltage"));
384 plotData.AddData(activePower, _("Active power"));
385 plotData.AddData(reactivePower, _("Reactive power"));
386 plotData.AddData(current, _("Current"));
387
388 return true;
389}
390
391rapidxml::xml_node<>* Load::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
392{
393 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "Load");
394 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
395
396 SaveCADProperties(doc, elementNode);
397
398 auto electricalProp = XMLParser::AppendNode(doc, elementNode, "ElectricalProperties");
399 auto isOnline = XMLParser::AppendNode(doc, electricalProp, "IsOnline");
400 XMLParser::SetNodeValue(doc, isOnline, m_online);
401 auto name = XMLParser::AppendNode(doc, electricalProp, "Name");
402 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
403 auto activePower = XMLParser::AppendNode(doc, electricalProp, "ActivePower");
404 XMLParser::SetNodeValue(doc, activePower, m_electricalData.activePower);
405 XMLParser::SetNodeAttribute(doc, activePower, "UnitID", static_cast<int>(m_electricalData.activePowerUnit));
406 auto reactivePower = XMLParser::AppendNode(doc, electricalProp, "ReactivePower");
407 XMLParser::SetNodeValue(doc, reactivePower, m_electricalData.reactivePower);
408 XMLParser::SetNodeAttribute(doc, reactivePower, "UnitID", static_cast<int>(m_electricalData.reactivePowerUnit));
409 auto loadType = XMLParser::AppendNode(doc, electricalProp, "LoadType");
410 XMLParser::SetNodeValue(doc, loadType, m_electricalData.loadType);
411
412 auto stability = XMLParser::AppendNode(doc, electricalProp, "Stability");
413 auto plotLoad = XMLParser::AppendNode(doc, stability, "PlotLoad");
414 XMLParser::SetNodeValue(doc, plotLoad, m_electricalData.plotLoad);
415 auto useCompLoad = XMLParser::AppendNode(doc, stability, "UseCompositeLoad");
416 XMLParser::SetNodeValue(doc, useCompLoad, m_electricalData.useCompLoad);
417 auto activePowerCompl = XMLParser::AppendNode(doc, stability, "ActivePowerComposition");
418 auto pzl = XMLParser::AppendNode(doc, activePowerCompl, "ConstantImpedance");
419 XMLParser::SetNodeValue(doc, pzl, m_electricalData.constImpedanceActive);
420 auto pil = XMLParser::AppendNode(doc, activePowerCompl, "ConstantCurrent");
421 XMLParser::SetNodeValue(doc, pil, m_electricalData.constCurrentActive);
422 auto ppl = XMLParser::AppendNode(doc, activePowerCompl, "ConstantPower");
423 XMLParser::SetNodeValue(doc, ppl, m_electricalData.constPowerActive);
424 auto reactivePowerCompl = XMLParser::AppendNode(doc, stability, "ReactivePowerComposition");
425 auto qzl = XMLParser::AppendNode(doc, reactivePowerCompl, "ConstantImpedance");
426 XMLParser::SetNodeValue(doc, qzl, m_electricalData.constImpedanceReactive);
427 auto qil = XMLParser::AppendNode(doc, reactivePowerCompl, "ConstantCurrent");
428 XMLParser::SetNodeValue(doc, qil, m_electricalData.constCurrentReactive);
429 auto qpl = XMLParser::AppendNode(doc, reactivePowerCompl, "ConstantPower");
430 XMLParser::SetNodeValue(doc, qpl, m_electricalData.constPowerReactive);
431
432 SaveSwitchingData(doc, electricalProp);
433
434 return elementNode;
435}
436
437bool Load::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
438{
439 if (!OpenCADProperties(elementNode, parentList)) return false;
440 // The load have to insert the points that define his triangle
441 m_triangPts.push_back(wxPoint2DDouble(-m_width / 2.0, -m_height / 2.0));
442 m_triangPts.push_back(wxPoint2DDouble(m_width / 2.0, -m_height / 2.0));
443 m_triangPts.push_back(wxPoint2DDouble(0.0, m_height / 2.0));
444
445 auto electricalProp = elementNode->first_node("ElectricalProperties");
446 if (!electricalProp) return false;
447
448 SetOnline(XMLParser::GetNodeValueInt(electricalProp, "IsOnline"));
449 m_electricalData.name = electricalProp->first_node("Name")->value();
450 m_electricalData.activePower = XMLParser::GetNodeValueDouble(electricalProp, "ActivePower");
451 m_electricalData.activePowerUnit =
452 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ActivePower", "UnitID"));
453 m_electricalData.reactivePower = XMLParser::GetNodeValueDouble(electricalProp, "ReactivePower");
454 m_electricalData.reactivePowerUnit =
455 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID"));
456 m_electricalData.loadType = static_cast<LoadType>(XMLParser::GetNodeValueInt(electricalProp, "LoadType"));
457 // Stability
458 auto stability = electricalProp->first_node("Stability");
459 if (stability) {
460 m_electricalData.plotLoad = XMLParser::GetNodeValueInt(stability, "PlotLoad");
461 m_electricalData.useCompLoad = XMLParser::GetNodeValueInt(stability, "UseCompositeLoad");
462 auto activePowerComp = stability->first_node("ActivePowerComposition");
463 m_electricalData.constImpedanceActive = XMLParser::GetNodeValueDouble(activePowerComp, "ConstantImpedance");
464 m_electricalData.constCurrentActive = XMLParser::GetNodeValueDouble(activePowerComp, "ConstantCurrent");
465 m_electricalData.constPowerActive = XMLParser::GetNodeValueDouble(activePowerComp, "ConstantPower");
466 auto reactivePowerComp = stability->first_node("ReactivePowerComposition");
467 m_electricalData.constImpedanceReactive = XMLParser::GetNodeValueDouble(reactivePowerComp, "ConstantImpedance");
468 m_electricalData.constCurrentReactive = XMLParser::GetNodeValueDouble(reactivePowerComp, "ConstantCurrent");
469 m_electricalData.constPowerReactive = XMLParser::GetNodeValueDouble(reactivePowerComp, "ConstantPower");
470 }
471
472 if (!OpenSwitchingData(electricalProp)) return false;
473 if (m_swData.swTime.size() != 0) SetDynamicEvent(true);
474
475 m_inserted = true;
476
477 return true;
478}
@ ID_EDIT_ELEMENT
Definition Element.h:77
PlotStudy
Node for power elements. All others power elements are connected through this.
Definition Bus.h:87
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition Element.h:115
virtual void GeneralMenuItens(wxMenu &menu)
Insert general itens to context menu.
Definition Element.cpp:475
wxPoint2DDouble GetPosition() const
Get the element position.
Definition Element.h:189
double GetAngle() const
Get the element angle.
Definition Element.h:214
virtual void DrawDCTriangle(std::vector< wxPoint2DDouble > points, wxGraphicsContext *gc) const
Draw rectangle.
Definition Element.cpp:209
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
Definition Element.cpp:298
virtual void AddChild(Element *child)
Add a child to the child list.
Definition Element.cpp:581
bool SetOnline(bool online=true)
Set if the element is online or offline.
Definition Element.cpp:465
virtual void DrawDCCircle(wxPoint2DDouble position, double radius, int numSegments, wxGraphicsContext *gc) const
Draw a circle using device context.
Definition Element.cpp:173
Form to edit the load power data.
Definition LoadForm.h:33
Loas shunt power element.
Definition Load.h:74
virtual wxString GetTipText() const
Get the tip text.
Definition Load.cpp:313
virtual void DrawDC(GUIColour *guiColour, wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
Definition Load.cpp:70
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition Load.cpp:227
virtual Element * GetCopy()
Get a the element copy.
Definition Load.cpp:306
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition Load.cpp:214
virtual bool AddParent(Element *parent, wxPoint2DDouble position, bool isOpening=false)
Add a parent to the element. This method must be used on power elements that connect to a bus,...
Definition Load.cpp:34
virtual bool GetPlotData(ElementPlotData &plotData, PlotStudy study=PlotStudy::STABILITY)
Fill the plot data.
Definition Load.cpp:368
virtual bool ShowForm(wxWindow *parent, Element *element, wxWindow *workspace=nullptr)
Show element data form.
Definition Load.cpp:245
virtual void SetDynamicEvent(bool dynEvent=true)
Set if the power element have dynamic event.
virtual void DrawDCPowerFlowPts(GUIColour *guiColour, wxGraphicsContext *gc) const
Draw power flow arrows.
virtual void UpdateSwitches()
Update the switch position.
virtual void DrawDCSwitches(GUIColour *guiColour, wxGraphicsContext *gc) const
Draw switch.
virtual wxPoint2DDouble GetSwitchPoint(Element *parent, wxPoint2DDouble parentPoint, wxPoint2DDouble secondPoint) const
Get the correct switch position.
Abstract class for shunt power elements.
Definition Shunt.h:32
std::vector< double > swTime