Power System Platform  2026w23a-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)
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}
138
139void Load::DrawDC(GUIColour* guiColour, wxPoint2DDouble translation, double scale, wxDC& dc) const
140{
141 wxColour elementColour;
142 if (m_online) {
143 if (m_dynEvent)
144 elementColour = guiColour->eventElement;
145 else
146 elementColour = guiColour->enabled;
147 }
148 else
149 elementColour = guiColour->disable;
150
151 std::vector<wxPoint> pointListInt;
152 for (auto& pt : m_pointList) {
153 pointListInt.emplace_back(static_cast<int>(pt.m_x), static_cast<int>(pt.m_y));
154 }
155 wxPoint pos = wxPoint(static_cast<int>(m_position.m_x), static_cast<int>(m_position.m_y));
156
157 if (m_inserted) {
158 // Draw Selection (layer 1).
159 if (m_selected) {
160 dc.SetPen(wxPen(guiColour->selection, 2 + m_borderSize * 2.0));
161 dc.SetBrush(*wxTRANSPARENT_BRUSH);
162
163 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
164
165 dc.SetPen(*wxTRANSPARENT_PEN);
166 dc.SetBrush(wxBrush(guiColour->selection));
167
168 wxPoint2DDouble p;
169 wxPoint selTriangPts[3];
170 p = m_triangPts[0] + m_position + wxPoint2DDouble(-m_borderSize / scale, -m_borderSize / scale);
171 selTriangPts[0] = RotateAround(p, m_position, m_angle);
172 p = m_triangPts[1] + m_position + wxPoint2DDouble(m_borderSize / scale, -m_borderSize / scale);
173 selTriangPts[1] = RotateAround(p, m_position, m_angle);
174 p = m_triangPts[2] + m_position + wxPoint2DDouble(0.0, m_borderSize / scale);
175 selTriangPts[2] = RotateAround(p, m_position, m_angle);
176
177 dc.DrawPolygon(3, selTriangPts);
178
179 // Draw node selection.
180 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, dc);
181 }
182
183 // Draw Load (layer 2).
184 dc.SetPen(wxPen(elementColour, 2));
185 dc.SetBrush(*wxTRANSPARENT_BRUSH);
186 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
187
188 // Draw node.
189 dc.SetPen(*wxTRANSPARENT_PEN);
190 dc.SetBrush(wxBrush(elementColour));
191 DrawDCCircle(m_pointList[0], 5.0, dc);
192
193 DrawDCSwitches(guiColour, dc);
194 DrawDCPowerFlowPts(guiColour, dc);
195
196 wxPoint2DDouble p;
197 wxPoint triangPts[3];
198
199 //std::vector<wxPoint2DDouble> triangPts;
200 for (int i = 0; i < 3; i++) {
201 p = m_triangPts[i] + m_position;
202 triangPts[i] = RotateAround(p, m_position, m_angle);
203 }
204 dc.SetPen(*wxTRANSPARENT_PEN);
205 dc.SetBrush(wxBrush(elementColour));
206 dc.DrawPolygon(3, triangPts);
207 }
208}
209
210void Load::Rotate(bool clockwise)
211{
212 double rotAngle = m_rotationAngle;
213 if (!clockwise) rotAngle = -m_rotationAngle;
214
215 m_angle += rotAngle;
216 if (m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
217 m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
218 m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
219 UpdateSwitchesPosition();
220 UpdatePowerFlowArrowsPosition();
221}
222
223bool Load::GetContextMenu(wxMenu& menu)
224{
225 menu.Append(ID_EDIT_ELEMENT, _("Edit Load"));
226
227 wxMenu* textMenu = new wxMenu();
228
229 textMenu->Append(ID_TXT_NAME, _("Name"));
230 textMenu->Append(ID_TXT_ACTIVE_POWER, _("Active power"));
231 textMenu->Append(ID_TXT_REACTIVE_POWER, _("Reactive power"));
232 textMenu->SetClientData(menu.GetClientData());
233
234
235 menu.AppendSubMenu(textMenu, _("Add text"));
236
237 GeneralMenuItens(menu);
238 return true;
239}
240
241bool Load::ShowForm(wxWindow* parent, Element* element, wxWindow* workspace)
242{
243 wxLogDebug("Before form constructor");
244 LoadForm loadForm(parent, this);
245 loadForm.CenterOnParent();
246 wxLogDebug("Before ShowModal");
247 if (loadForm.ShowModal() == wxID_OK) {
248 wxLogDebug("After ShowModal");
249 return true;
250 }
251 return false;
252}
253
254LoadElectricalData Load::GetPUElectricalData(double systemPowerBase)
255{
257
258 data.name = m_electricalData.name;
259
260 data.activePower = m_electricalData.activePower;
261 data.activePowerUnit = m_electricalData.activePowerUnit;
262
263 data.reactivePower = m_electricalData.reactivePower;
264 data.reactivePowerUnit = m_electricalData.reactivePowerUnit;
265
266 switch (data.activePowerUnit) {
267 case ElectricalUnit::UNIT_W: {
268 data.activePower = data.activePower / systemPowerBase;
269 data.activePowerUnit = ElectricalUnit::UNIT_PU;
270 } break;
271 case ElectricalUnit::UNIT_kW: {
272 data.activePower = (data.activePower * 1e3) / systemPowerBase;
273 data.activePowerUnit = ElectricalUnit::UNIT_PU;
274 } break;
275 case ElectricalUnit::UNIT_MW: {
276 data.activePower = (data.activePower * 1e6) / systemPowerBase;
277 data.activePowerUnit = ElectricalUnit::UNIT_PU;
278 } break;
279 default:
280 break;
281 }
282 switch (data.reactivePowerUnit) {
283 case ElectricalUnit::UNIT_var: {
284 data.reactivePower = data.reactivePower / systemPowerBase;
285 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
286 } break;
287 case ElectricalUnit::UNIT_kvar: {
288 data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
289 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
290 } break;
291 case ElectricalUnit::UNIT_Mvar: {
292 data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
293 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
294 } break;
295 default:
296 break;
297 }
298
299 return data;
300}
301
303{
304 Load* copy = new Load();
305 *copy = *this;
306 return copy;
307}
308
309wxString Load::GetTipText() const
310{
311 wxString tipText = m_electricalData.name;
312
313 // TODO: Avoid power calculation.
314 double activePower = m_electricalData.activePower;
315 double reactivePower = m_electricalData.reactivePower;
316 if (!m_online) {
317 activePower = 0.0;
318 reactivePower = 0.0;
319 }
320 if (m_online && m_electricalData.loadType == CONST_IMPEDANCE) {
321 std::complex<double> v = static_cast<Bus*>(m_parentList[0])->GetElectricalData().voltage;
322 reactivePower *= std::pow(std::abs(v), 2);
323 activePower *= std::pow(std::abs(v), 2);
324 }
325 tipText += "\n";
326 tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
327 switch (m_electricalData.activePowerUnit) {
328 case ElectricalUnit::UNIT_PU: {
329 tipText += _(" p.u.");
330 } break;
331 case ElectricalUnit::UNIT_W: {
332 tipText += _(" W");
333 } break;
334 case ElectricalUnit::UNIT_kW: {
335 tipText += _(" kW");
336 } break;
337 case ElectricalUnit::UNIT_MW: {
338 tipText += _(" MW");
339 } break;
340 default:
341 break;
342 }
343 tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
344 switch (m_electricalData.reactivePowerUnit) {
345 case ElectricalUnit::UNIT_PU: {
346 tipText += _(" p.u.");
347 } break;
348 case ElectricalUnit::UNIT_var: {
349 tipText += _(" var");
350 } break;
351 case ElectricalUnit::UNIT_kvar: {
352 tipText += _(" kvar");
353 } break;
354 case ElectricalUnit::UNIT_Mvar: {
355 tipText += _(" Mvar");
356 } break;
357 default:
358 break;
359 }
360
361 return tipText;
362}
363
365{
366 if (!m_electricalData.plotLoad) return false;
367 plotData.SetName(m_electricalData.name);
368 plotData.SetCurveType(ElementPlotData::CurveType::CT_LOAD);
369
370 std::vector<double> absVoltage, activePower, reactivePower, current;
371 for (unsigned int i = 0; i < m_electricalData.voltageVector.size(); ++i) {
372 absVoltage.push_back(std::abs(m_electricalData.voltageVector[i]));
373 activePower.push_back(std::real(m_electricalData.electricalPowerVector[i]));
374 reactivePower.push_back(std::imag(m_electricalData.electricalPowerVector[i]));
375 current.push_back(std::abs(std::complex<double>(activePower[i], -reactivePower[i]) /
376 std::conj(m_electricalData.voltageVector[i])));
377 }
378
379 plotData.AddData(absVoltage, _("Voltage"));
380 plotData.AddData(activePower, _("Active power"));
381 plotData.AddData(reactivePower, _("Reactive power"));
382 plotData.AddData(current, _("Current"));
383
384 return true;
385}
386
387rapidxml::xml_node<>* Load::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
388{
389 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "Load");
390 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
391
392 SaveCADProperties(doc, elementNode);
393
394 auto electricalProp = XMLParser::AppendNode(doc, elementNode, "ElectricalProperties");
395 auto isOnline = XMLParser::AppendNode(doc, electricalProp, "IsOnline");
396 XMLParser::SetNodeValue(doc, isOnline, m_online);
397 auto name = XMLParser::AppendNode(doc, electricalProp, "Name");
398 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
399 auto activePower = XMLParser::AppendNode(doc, electricalProp, "ActivePower");
400 XMLParser::SetNodeValue(doc, activePower, m_electricalData.activePower);
401 XMLParser::SetNodeAttribute(doc, activePower, "UnitID", static_cast<int>(m_electricalData.activePowerUnit));
402 auto reactivePower = XMLParser::AppendNode(doc, electricalProp, "ReactivePower");
403 XMLParser::SetNodeValue(doc, reactivePower, m_electricalData.reactivePower);
404 XMLParser::SetNodeAttribute(doc, reactivePower, "UnitID", static_cast<int>(m_electricalData.reactivePowerUnit));
405 auto loadType = XMLParser::AppendNode(doc, electricalProp, "LoadType");
406 XMLParser::SetNodeValue(doc, loadType, m_electricalData.loadType);
407
408 auto stability = XMLParser::AppendNode(doc, electricalProp, "Stability");
409 auto plotLoad = XMLParser::AppendNode(doc, stability, "PlotLoad");
410 XMLParser::SetNodeValue(doc, plotLoad, m_electricalData.plotLoad);
411 auto useCompLoad = XMLParser::AppendNode(doc, stability, "UseCompositeLoad");
412 XMLParser::SetNodeValue(doc, useCompLoad, m_electricalData.useCompLoad);
413 auto activePowerCompl = XMLParser::AppendNode(doc, stability, "ActivePowerComposition");
414 auto pzl = XMLParser::AppendNode(doc, activePowerCompl, "ConstantImpedance");
415 XMLParser::SetNodeValue(doc, pzl, m_electricalData.constImpedanceActive);
416 auto pil = XMLParser::AppendNode(doc, activePowerCompl, "ConstantCurrent");
417 XMLParser::SetNodeValue(doc, pil, m_electricalData.constCurrentActive);
418 auto ppl = XMLParser::AppendNode(doc, activePowerCompl, "ConstantPower");
419 XMLParser::SetNodeValue(doc, ppl, m_electricalData.constPowerActive);
420 auto reactivePowerCompl = XMLParser::AppendNode(doc, stability, "ReactivePowerComposition");
421 auto qzl = XMLParser::AppendNode(doc, reactivePowerCompl, "ConstantImpedance");
422 XMLParser::SetNodeValue(doc, qzl, m_electricalData.constImpedanceReactive);
423 auto qil = XMLParser::AppendNode(doc, reactivePowerCompl, "ConstantCurrent");
424 XMLParser::SetNodeValue(doc, qil, m_electricalData.constCurrentReactive);
425 auto qpl = XMLParser::AppendNode(doc, reactivePowerCompl, "ConstantPower");
426 XMLParser::SetNodeValue(doc, qpl, m_electricalData.constPowerReactive);
427
428 SaveSwitchingData(doc, electricalProp);
429
430 return elementNode;
431}
432
433bool Load::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
434{
435 if (!OpenCADProperties(elementNode, parentList)) return false;
436 // The load have to insert the points that define his triangle
437 m_triangPts.push_back(wxPoint2DDouble(-m_width / 2.0, -m_height / 2.0));
438 m_triangPts.push_back(wxPoint2DDouble(m_width / 2.0, -m_height / 2.0));
439 m_triangPts.push_back(wxPoint2DDouble(0.0, m_height / 2.0));
440
441 auto electricalProp = elementNode->first_node("ElectricalProperties");
442 if (!electricalProp) return false;
443
444 SetOnline(XMLParser::GetNodeValueInt(electricalProp, "IsOnline"));
445 m_electricalData.name = electricalProp->first_node("Name")->value();
446 m_electricalData.activePower = XMLParser::GetNodeValueDouble(electricalProp, "ActivePower");
447 m_electricalData.activePowerUnit =
448 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ActivePower", "UnitID"));
449 m_electricalData.reactivePower = XMLParser::GetNodeValueDouble(electricalProp, "ReactivePower");
450 m_electricalData.reactivePowerUnit =
451 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID"));
452 m_electricalData.loadType = static_cast<LoadType>(XMLParser::GetNodeValueInt(electricalProp, "LoadType"));
453 // Stability
454 auto stability = electricalProp->first_node("Stability");
455 if (stability) {
456 m_electricalData.plotLoad = XMLParser::GetNodeValueInt(stability, "PlotLoad");
457 m_electricalData.useCompLoad = XMLParser::GetNodeValueInt(stability, "UseCompositeLoad");
458 auto activePowerComp = stability->first_node("ActivePowerComposition");
459 m_electricalData.constImpedanceActive = XMLParser::GetNodeValueDouble(activePowerComp, "ConstantImpedance");
460 m_electricalData.constCurrentActive = XMLParser::GetNodeValueDouble(activePowerComp, "ConstantCurrent");
461 m_electricalData.constPowerActive = XMLParser::GetNodeValueDouble(activePowerComp, "ConstantPower");
462 auto reactivePowerComp = stability->first_node("ReactivePowerComposition");
463 m_electricalData.constImpedanceReactive = XMLParser::GetNodeValueDouble(reactivePowerComp, "ConstantImpedance");
464 m_electricalData.constCurrentReactive = XMLParser::GetNodeValueDouble(reactivePowerComp, "ConstantCurrent");
465 m_electricalData.constPowerReactive = XMLParser::GetNodeValueDouble(reactivePowerComp, "ConstantPower");
466 }
467
468 if (!OpenSwitchingData(electricalProp)) return false;
469 if (m_swData.swTime.size() != 0) SetDynamicEvent(true);
470
471 m_inserted = true;
472
473 return true;
474}
@ ID_EDIT_ELEMENT
Definition Element.h:77
PlotStudy
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:114
virtual void GeneralMenuItens(wxMenu &menu)
Insert general itens to context menu.
Definition Element.cpp:393
wxPoint2DDouble GetPosition() const
Get the element position.
Definition Element.h:188
double GetAngle() const
Get the element angle.
Definition Element.h:213
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:228
virtual void AddChild(Element *child)
Add a child to the child list.
Definition Element.cpp:499
bool SetOnline(bool online=true)
Set if the element is online or offline.
Definition Element.cpp:383
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:309
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:223
virtual Element * GetCopy()
Get a the element copy.
Definition Load.cpp:302
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition Load.cpp:210
virtual bool GetPlotData(ElementPlotData &plotData, PlotStudy study=PlotStudy::STABILITY)
Fill the plot data.
Definition Load.cpp:364
virtual bool ShowForm(wxWindow *parent, Element *element, wxWindow *workspace=nullptr)
Show element data form.
Definition Load.cpp:241
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 Load.cpp:34
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