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