Power System Platform  2026w34a-beta
Loading...
Searching...
No Matches
Inductor.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 "Inductor.h"
19#include "../../forms/ReactiveShuntElementForm.h"
20
21Inductor::Inductor() : Shunt()
22{
23 m_elementType = TYPE_INDUCTOR;
24}
25
26Inductor::Inductor(wxString name) : Shunt()
27{
28 m_elementType = TYPE_INDUCTOR;
29 m_electricalData.name = name;
30}
31
32Inductor::~Inductor() {}
33
34bool Inductor::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 = 20.0;
46 m_height = 70.0;
47 m_rect = wxRect2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0, m_width, m_height);
48
49 m_pointList.push_back(parentPt);
50 m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
51 m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0 - 10.0));
52 m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0));
53
54 m_inserted = true;
55
56 wxRect2DDouble genRect(0, 0, 0, 0);
57 m_switchRect.push_back(genRect); // Push a general rectangle.
59
60 return true;
61 }
62 return false;
63}
64
65//void Inductor::Draw(wxPoint2DDouble translation, double scale) const
66//{
67// OpenGLColour elementColour;
68// if (m_online) {
69// if (m_dynEvent)
70// elementColour = m_dynamicEventColour;
71// else
72// elementColour = m_onlineElementColour;
73// }
74// else
75// elementColour = m_offlineElementColour;
76//
77// if (m_inserted) {
78// if (m_selected) {
79// glLineWidth(1.5 + m_borderSize * 2.0);
80// glColor4dv(m_selectionColour.GetRGBA());
81//
82// DrawLine(m_pointList);
83//
84// glPushMatrix();
85// glTranslated(m_position.m_x, m_position.m_y, 0.0);
86// glRotated(m_angle, 0.0, 0.0, 1.0);
87// glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
88//
89// DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), 10, 45, 270, 30, GL_LINE_STRIP);
90// DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0), 10, 45, 315, 30, GL_LINE_STRIP);
91// DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0), 10, 90, 315, 30, GL_LINE_STRIP);
92//
93// DrawGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0));
94//
95// glPopMatrix();
96//
97// // Draw node selection.
98// DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
99// }
100// // Draw Load (layer 2).
101// glLineWidth(1.5);
102// glColor4dv(elementColour.GetRGBA());
103// DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
104// DrawLine(m_pointList);
105//
106// DrawSwitches();
107//
108// glPushMatrix();
109// glTranslated(m_position.m_x, m_position.m_y, 0.0);
110// glRotated(m_angle, 0.0, 0.0, 1.0);
111// glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
112//
113// glColor4dv(elementColour.GetRGBA());
114// DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), 10, 45, 270, 10, GL_LINE_STRIP);
115// DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0), 10, 45, 315, 10, GL_LINE_STRIP);
116// DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0), 10, 90, 315, 10, GL_LINE_STRIP);
117//
118// DrawGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0));
119//
120// glPopMatrix();
121// }
122//}
123
124void Inductor::DrawDC(GUIColour* guiColour, wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const
125{
126 wxColour elementColour;
127 if (m_online) {
128 //if (m_dynEvent)
129 // elementColour = guiColour->eventElement;
130 //else
131 elementColour = guiColour->enabled;
132 }
133 else
134 elementColour = guiColour->disable;
135
136 if (m_inserted) {
137 if (m_selected) {
138 gc->SetPen(wxPen(guiColour->selection, 2 + m_borderSize * 2.0));
139 gc->SetBrush(*wxTRANSPARENT_BRUSH);
140
141 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
142
143 // Push the current matrix on stack.
144 gc->PushState();
145 // Rotate the matrix around the object position.
146 gc->Translate(m_position.m_x, m_position.m_y);
147 gc->Rotate(wxDegToRad(m_angle));
148 gc->Translate(-m_position.m_x, -m_position.m_y);
149
150 DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), 10, 45, 270, 30, gc);
151 DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0), 10, 45, 315, 30, gc);
152 DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0), 10, 90, 315, 30, gc);
153
154 DrawDCGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0), gc);
155
156 gc->PopState();
157
158 // Draw node selection.
159 gc->SetPen(*wxTRANSPARENT_PEN);
160 gc->SetBrush(wxBrush(guiColour->selection));
161 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc);
162 }
163 // Draw Inductor (layer 2).
164 gc->SetPen(*wxTRANSPARENT_PEN);
165 gc->SetBrush(wxBrush(wxColour(elementColour)));
166 DrawDCCircle(m_pointList[0], 5.0, 10, gc);
167
168 gc->SetPen(wxPen(wxColour(elementColour), 2));
169 gc->SetBrush(*wxTRANSPARENT_BRUSH);
170 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
171
172 DrawDCSwitches(guiColour, gc);
173
174 // Push the current matrix on stack.
175 gc->PushState();
176 // Rotate the matrix around the object position.
177 gc->Translate(m_position.m_x, m_position.m_y);
178 gc->Rotate(wxDegToRad(m_angle));
179 gc->Translate(-m_position.m_x, -m_position.m_y);
180
181 gc->SetPen(wxPen(wxColour(elementColour), 2));
182 gc->SetBrush(*wxTRANSPARENT_BRUSH);
183 DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), 10, 45, 270, 10, gc);
184 DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0), 10, 45, 315, 10, gc);
185 DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0), 10, 90, 315, 10, gc);
186
187 DrawDCGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0), gc);
188
189 gc->PopState();
190
191 if (m_dynEvent) {
192 DrawStabilityEventGC(gc, translation, scale, guiColour);
193 }
194 }
195}
196
197void Inductor::DrawDC(GUIColour* guiColour, wxPoint2DDouble translation, double scale, wxDC& dc) const
198{
199 wxColour elementColour;
200 if (m_online) {
201 if (m_dynEvent)
202 elementColour = guiColour->eventElement;
203 else
204 elementColour = guiColour->enabled;
205 }
206 else
207 elementColour = guiColour->disable;
208
209 std::vector<wxPoint> pointListInt;
210 for (auto& pt : m_pointList) {
211 pointListInt.emplace_back(static_cast<int>(pt.m_x), static_cast<int>(pt.m_y));
212 }
213
214 if (m_inserted) {
215 wxPoint arcPts[3];
216 wxPoint2DDouble p;
217 p = m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0);
218 arcPts[0] = RotateAround(p, m_position, m_angle);
219 p = m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0);
220 arcPts[1] = RotateAround(p, m_position, m_angle);
221 p = m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0);
222 arcPts[2] = RotateAround(p, m_position, m_angle);
223
224 if (m_selected) {
225 dc.SetPen(wxPen(guiColour->selection, 2 + m_borderSize * 2.0));
226 dc.SetBrush(*wxTRANSPARENT_BRUSH);
227
228 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
229
230 DrawDCArc(arcPts[0], 10, 90 - m_angle, 315 - m_angle, dc);
231 DrawDCArc(arcPts[1], 10, 45 - m_angle, 315 - m_angle, dc);
232 DrawDCArc(arcPts[2], 10, 45 - m_angle, 270 - m_angle, dc);
233
234 DrawDCGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0), dc);
235
236 // Draw node selection.
237 dc.SetPen(*wxTRANSPARENT_PEN);
238 dc.SetBrush(wxBrush(guiColour->selection));
239 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, dc);
240 }
241 // Draw Inductor (layer 2).
242 dc.SetPen(*wxTRANSPARENT_PEN);
243 dc.SetBrush(wxBrush(wxColour(elementColour)));
244 DrawDCCircle(m_pointList[0], 5.0, dc);
245
246 dc.SetPen(wxPen(wxColour(elementColour), 2));
247 dc.SetBrush(*wxTRANSPARENT_BRUSH);
248 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
249
250 DrawDCSwitches(guiColour, dc);
251
252 dc.SetPen(wxPen(wxColour(elementColour), 2));
253 dc.SetBrush(*wxTRANSPARENT_BRUSH);
254 DrawDCArc(arcPts[0], 10, 90 - m_angle, 315 - m_angle, dc);
255 DrawDCArc(arcPts[1], 10, 45 - m_angle, 315 - m_angle, dc);
256 DrawDCArc(arcPts[2], 10, 45 - m_angle, 270 - m_angle, dc);
257
258 DrawDCGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0), dc);
259 }
260}
261
262void Inductor::Rotate(bool clockwise)
263{
264 double rotAngle = m_rotationAngle;
265 if (!clockwise) rotAngle = -m_rotationAngle;
266
267 m_angle += rotAngle;
268 if (m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
269 m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
270 m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
271 UpdateSwitchesPosition();
272}
273
274bool Inductor::GetContextMenu(wxMenu& menu)
275{
276 menu.Append(ID_EDIT_ELEMENT, _("Edit Inductor"));
277
278 wxMenu* textMenu = new wxMenu();
279
280 textMenu->Append(ID_TXT_NAME, _("Name"));
281 textMenu->Append(ID_TXT_REACTIVE_POWER, _("Reactive power"));
282 textMenu->SetClientData(menu.GetClientData());
283 menu.AppendSubMenu(textMenu, _("Add text"));
284
285 GeneralMenuItens(menu);
286 return true;
287}
288
289bool Inductor::Contains(wxPoint2DDouble position) const
290{
291 wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
292 return m_rect.Contains(ptR);
293}
294
295bool Inductor::Intersects(wxRect2DDouble rect) const { return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0); }
296bool Inductor::ShowForm(wxWindow* parent, Element* element, wxWindow* workspace)
297{
298 ReactiveShuntElementForm inductorForm(parent, this);
299 inductorForm.SetTitle(_("Inductor"));
300 inductorForm.CenterOnParent();
301 if (inductorForm.ShowModal() == wxID_OK) {
302 return true;
303 }
304 return false;
305}
306
307InductorElectricalData Inductor::GetPUElectricalData(double systemPowerBase)
308{
309 InductorElectricalData data = m_electricalData;
310 switch (data.reactivePowerUnit) {
311 case ElectricalUnit::UNIT_var: {
312 data.reactivePower = data.reactivePower / systemPowerBase;
313 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
314 } break;
315 case ElectricalUnit::UNIT_kvar: {
316 data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
317 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
318 } break;
319 case ElectricalUnit::UNIT_Mvar: {
320 data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
321 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
322 } break;
323 default:
324 break;
325 }
326
327 return data;
328}
329
331{
332 Inductor* copy = new Inductor();
333 *copy = *this;
334 return copy;
335}
336
337wxString Inductor::GetTipText() const
338{
339 wxString tipText = m_electricalData.name;
340
341 // TODO: Avoid reactive power calculation.
342 double reactivePower = m_electricalData.reactivePower;
343 if (!m_online)
344 reactivePower = 0.0;
345 else {
346 std::complex<double> v = static_cast<Bus*>(m_parentList[0])->GetElectricalData().voltage;
347 reactivePower *= std::pow(std::abs(v), 2);
348 }
349 tipText += "\n";
350 tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
351 switch (m_electricalData.reactivePowerUnit) {
352 case ElectricalUnit::UNIT_PU: {
353 tipText += _(" p.u.");
354 } break;
355 case ElectricalUnit::UNIT_var: {
356 tipText += _(" var");
357 } break;
358 case ElectricalUnit::UNIT_kvar: {
359 tipText += _(" kvar");
360 } break;
361 case ElectricalUnit::UNIT_Mvar: {
362 tipText += _(" Mvar");
363 } break;
364 default:
365 break;
366 }
367
368 return tipText;
369}
370
371rapidxml::xml_node<>* Inductor::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
372{
373 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "Inductor");
374 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
375
376 SaveCADProperties(doc, elementNode);
377
378 auto electricalProp = XMLParser::AppendNode(doc, elementNode, "ElectricalProperties");
379 auto isOnline = XMLParser::AppendNode(doc, electricalProp, "IsOnline");
380 XMLParser::SetNodeValue(doc, isOnline, m_online);
381 auto name = XMLParser::AppendNode(doc, electricalProp, "Name");
382 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
383 auto reactivePower = XMLParser::AppendNode(doc, electricalProp, "ReactivePower");
384 XMLParser::SetNodeValue(doc, reactivePower, m_electricalData.reactivePower);
385 XMLParser::SetNodeAttribute(doc, reactivePower, "UnitID", static_cast<int>(m_electricalData.reactivePowerUnit));
386
387 SaveSwitchingData(doc, electricalProp);
388
389 return elementNode;
390}
391
392bool Inductor::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
393{
394 if (!OpenCADProperties(elementNode, parentList)) return false;
395
396 auto electricalProp = elementNode->first_node("ElectricalProperties");
397 if (!electricalProp) return false;
398
399 SetOnline(XMLParser::GetNodeValueInt(electricalProp, "IsOnline"));
400 m_electricalData.name = electricalProp->first_node("Name")->value();
401 m_electricalData.reactivePower = XMLParser::GetNodeValueDouble(electricalProp, "ReactivePower");
402 m_electricalData.reactivePowerUnit =
403 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID"));
404
405 if (!OpenSwitchingData(electricalProp)) return false;
406 if (m_swData.swTime.size() != 0) SetDynamicEvent(true);
407
408 m_inserted = true;
409 return true;
410}
@ ID_EDIT_ELEMENT
Definition Element.h:77
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 bool RotatedRectanglesIntersects(wxRect2DDouble rect1, wxRect2DDouble rect2, double angle1, double angle2) const
Check if two roteted rectangles intersect.
Definition Element.cpp:377
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 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
Inductor shunt power element.
Definition Inductor.h:39
virtual bool ShowForm(wxWindow *parent, Element *element, wxWindow *workspace=nullptr)
Show element data form.
Definition Inductor.cpp:296
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element's rect intersects other rect.
Definition Inductor.cpp:295
virtual Element * GetCopy()
Get a the element copy.
Definition Inductor.cpp:330
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition Inductor.cpp:262
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition Inductor.cpp:274
virtual wxString GetTipText() const
Get the tip text.
Definition Inductor.cpp:337
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition Inductor.cpp:289
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 Inductor.cpp:34
virtual void DrawDC(GUIColour *guiColour, wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
Definition Inductor.cpp:124
virtual void SetDynamicEvent(bool dynEvent=true)
Set if the power element have dynamic event.
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.
Form to edit the reactive shunt element power data.
Abstract class for shunt power elements.
Definition Shunt.h:32
std::vector< double > swTime