Power System Platform  2026w10a-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)
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(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const
125{
126 wxColour elementColour;
127 if (m_online) {
128 if (m_dynEvent)
129 elementColour = m_dynamicEventColour;
130 else
131 elementColour = m_onlineElementColour;
132 }
133 else
134 elementColour = m_offlineElementColour;
135
136 if (m_inserted) {
137 if (m_selected) {
138 gc->SetPen(wxPen(wxColour(m_selectionColour), 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(wxColour(m_selectionColour)));
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(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}
192
193void Inductor::DrawDC(wxPoint2DDouble translation, double scale, wxDC& dc) const
194{
195 wxColour elementColour;
196 if (m_online) {
197 if (m_dynEvent)
198 elementColour = m_dynamicEventColour;
199 else
200 elementColour = m_onlineElementColour;
201 }
202 else
203 elementColour = m_offlineElementColour;
204
205 std::vector<wxPoint> pointListInt;
206 for (auto& pt : m_pointList) {
207 pointListInt.emplace_back(static_cast<int>(pt.m_x), static_cast<int>(pt.m_y));
208 }
209
210 if (m_inserted) {
211 wxPoint arcPts[3];
212 wxPoint2DDouble p;
213 p = m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0);
214 arcPts[0] = RotateAround(p, m_position, m_angle);
215 p = m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0);
216 arcPts[1] = RotateAround(p, m_position, m_angle);
217 p = m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0);
218 arcPts[2] = RotateAround(p, m_position, m_angle);
219
220 if (m_selected) {
221 dc.SetPen(wxPen(wxColour(m_selectionColour), 2 + m_borderSize * 2.0));
222 dc.SetBrush(*wxTRANSPARENT_BRUSH);
223
224 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
225
226 DrawDCArc(arcPts[0], 10, 90 - m_angle, 315 - m_angle, dc);
227 DrawDCArc(arcPts[1], 10, 45 - m_angle, 315 - m_angle, dc);
228 DrawDCArc(arcPts[2], 10, 45 - m_angle, 270 - m_angle, dc);
229
230 DrawDCGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0), dc);
231
232 // Draw node selection.
233 dc.SetPen(*wxTRANSPARENT_PEN);
234 dc.SetBrush(wxBrush(wxColour(m_selectionColour)));
235 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, dc);
236 }
237 // Draw Inductor (layer 2).
238 dc.SetPen(*wxTRANSPARENT_PEN);
239 dc.SetBrush(wxBrush(wxColour(elementColour)));
240 DrawDCCircle(m_pointList[0], 5.0, dc);
241
242 dc.SetPen(wxPen(wxColour(elementColour), 2));
243 dc.SetBrush(*wxTRANSPARENT_BRUSH);
244 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
245
246 DrawDCSwitches(dc);
247
248 dc.SetPen(wxPen(wxColour(elementColour), 2));
249 dc.SetBrush(*wxTRANSPARENT_BRUSH);
250 DrawDCArc(arcPts[0], 10, 90 - m_angle, 315 - m_angle, dc);
251 DrawDCArc(arcPts[1], 10, 45 - m_angle, 315 - m_angle, dc);
252 DrawDCArc(arcPts[2], 10, 45 - m_angle, 270 - m_angle, dc);
253
254 DrawDCGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0), dc);
255 }
256}
257
258void Inductor::Rotate(bool clockwise)
259{
260 double rotAngle = m_rotationAngle;
261 if (!clockwise) rotAngle = -m_rotationAngle;
262
263 m_angle += rotAngle;
264 if (m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
265 m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
266 m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
267 UpdateSwitchesPosition();
268}
269
270bool Inductor::GetContextMenu(wxMenu& menu)
271{
272 menu.Append(ID_EDIT_ELEMENT, _("Edit Inductor"));
273
274 wxMenu* textMenu = new wxMenu();
275
276 textMenu->Append(ID_TXT_NAME, _("Name"));
277 textMenu->Append(ID_TXT_REACTIVE_POWER, _("Reactive power"));
278 textMenu->SetClientData(menu.GetClientData());
279 menu.AppendSubMenu(textMenu, _("Add text"));
280
281 GeneralMenuItens(menu);
282 return true;
283}
284
285bool Inductor::Contains(wxPoint2DDouble position) const
286{
287 wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
288 return m_rect.Contains(ptR);
289}
290
291bool Inductor::Intersects(wxRect2DDouble rect) const { return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0); }
292bool Inductor::ShowForm(wxWindow* parent, Element* element)
293{
294 ReactiveShuntElementForm inductorForm(parent, this);
295 inductorForm.SetTitle(_("Inductor"));
296 inductorForm.CenterOnParent();
297 if (inductorForm.ShowModal() == wxID_OK) {
298 return true;
299 }
300 return false;
301}
302
303InductorElectricalData Inductor::GetPUElectricalData(double systemPowerBase)
304{
305 InductorElectricalData data = m_electricalData;
306 switch (data.reactivePowerUnit) {
308 data.reactivePower = data.reactivePower / systemPowerBase;
309 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
310 } break;
312 data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
313 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
314 } break;
316 data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
317 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
318 } break;
319 default:
320 break;
321 }
322
323 return data;
324}
325
327{
328 Inductor* copy = new Inductor();
329 *copy = *this;
330 return copy;
331}
332
333wxString Inductor::GetTipText() const
334{
335 wxString tipText = m_electricalData.name;
336
337 // TODO: Avoid reactive power calculation.
338 double reactivePower = m_electricalData.reactivePower;
339 if (!m_online)
340 reactivePower = 0.0;
341 else {
342 std::complex<double> v = static_cast<Bus*>(m_parentList[0])->GetElectricalData().voltage;
343 reactivePower *= std::pow(std::abs(v), 2);
344 }
345 tipText += "\n";
346 tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
347 switch (m_electricalData.reactivePowerUnit) {
349 tipText += _(" p.u.");
350 } break;
352 tipText += _(" var");
353 } break;
355 tipText += _(" kvar");
356 } break;
358 tipText += _(" Mvar");
359 } break;
360 default:
361 break;
362 }
363
364 return tipText;
365}
366
367rapidxml::xml_node<>* Inductor::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
368{
369 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "Inductor");
370 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
371
372 SaveCADProperties(doc, elementNode);
373
374 auto electricalProp = XMLParser::AppendNode(doc, elementNode, "ElectricalProperties");
375 auto isOnline = XMLParser::AppendNode(doc, electricalProp, "IsOnline");
376 XMLParser::SetNodeValue(doc, isOnline, m_online);
377 auto name = XMLParser::AppendNode(doc, electricalProp, "Name");
378 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
379 auto reactivePower = XMLParser::AppendNode(doc, electricalProp, "ReactivePower");
380 XMLParser::SetNodeValue(doc, reactivePower, m_electricalData.reactivePower);
381 XMLParser::SetNodeAttribute(doc, reactivePower, "UnitID", static_cast<int>(m_electricalData.reactivePowerUnit));
382
383 SaveSwitchingData(doc, electricalProp);
384
385 return elementNode;
386}
387
388bool Inductor::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
389{
390 if (!OpenCADProperties(elementNode, parentList)) return false;
391
392 auto electricalProp = elementNode->first_node("ElectricalProperties");
393 if (!electricalProp) return false;
394
395 SetOnline(XMLParser::GetNodeValueInt(electricalProp, "IsOnline"));
396 m_electricalData.name = electricalProp->first_node("Name")->value();
397 m_electricalData.reactivePower = XMLParser::GetNodeValueDouble(electricalProp, "ReactivePower");
398 m_electricalData.reactivePowerUnit =
399 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID"));
400
401 if (!OpenSwitchingData(electricalProp)) return false;
402 if (m_swData.swTime.size() != 0) SetDynamicEvent(true);
403
404 m_inserted = true;
405 return true;
406}
@ ID_EDIT_ELEMENT
Definition Element.h:75
ElectricalUnit
Electrical units.
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 RotatedRectanglesIntersects(wxRect2DDouble rect1, wxRect2DDouble rect2, double angle1, double angle2) const
Check if two roteted rectangles intersect.
Definition Element.cpp:359
virtual void GeneralMenuItens(wxMenu &menu)
Insert general itens to context menu.
Definition Element.cpp:457
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:292
virtual void AddChild(Element *child)
Add a child to the child list.
Definition Element.cpp:566
bool SetOnline(bool online=true)
Set if the element is online or offline.
Definition Element.cpp:447
virtual void DrawDCCircle(wxPoint2DDouble position, double radius, int numSegments, wxGraphicsContext *gc) const
Draw a circle using device context.
Definition Element.cpp:177
Inductor shunt power element.
Definition Inductor.h:39
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element's rect intersects other rect.
Definition Inductor.cpp:291
virtual Element * GetCopy()
Get a the element copy.
Definition Inductor.cpp:326
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 Inductor.cpp:34
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition Inductor.cpp:258
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition Inductor.cpp:270
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition Inductor.cpp:292
virtual wxString GetTipText() const
Get the tip text.
Definition Inductor.cpp:333
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition Inductor.cpp:285
virtual void DrawDC(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 DrawDCSwitches(wxGraphicsContext *gc) const
Draw switch.
virtual void UpdateSwitches()
Update the switch position.
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