Power System Platform  2026w10a-beta
Loading...
Searching...
No Matches
HarmCurrent.cpp
1#include "HarmCurrent.h"
2
3#include "../../forms/HarmCurrentForm.h"
4
5HarmCurrent::HarmCurrent() : Shunt() {}
6
7HarmCurrent::~HarmCurrent() {}
8
9HarmCurrent::HarmCurrent(wxString name) : Shunt() { m_electricalData.name = name; }
10
12{
13 HarmCurrent* copy = new HarmCurrent();
14 *copy = *this;
15 return copy;
16}
17
18bool HarmCurrent::AddParent(Element* parent, wxPoint2DDouble position)
19{
20 if (parent) {
21 m_parentList.push_back(parent);
22 parent->AddChild(this);
23 wxPoint2DDouble parentPt =
24 parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
25 parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
26 parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
27
28 m_position = parentPt + wxPoint2DDouble(0.0, 100.0); // Shifts the position to the down of the bus.
29 m_width = 40;
30 m_height = 60;
31 m_rect = wxRect2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0, m_width, m_height);
32
33 m_pointList.push_back(parentPt);
34 m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
35 m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0 - 10.0));
36 m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0));
37
38 m_triangPts.push_back(wxPoint2DDouble(-5, -15));
39 m_triangPts.push_back(wxPoint2DDouble(5, -15));
40 m_triangPts.push_back(wxPoint2DDouble(0.0, -30.0));
41
42 m_inserted = true;
43
44 wxRect2DDouble genRect(0, 0, 0, 0);
45 m_switchRect.push_back(genRect); // Push a general rectangle.
47
48 return true;
49 }
50 return false;
51}
52
53//void HarmCurrent::Draw(wxPoint2DDouble translation, double scale) const
54//{
55// OpenGLColour elementColour;
56// if(m_online) {
57// if(m_dynEvent)
58// elementColour = m_dynamicEventColour;
59// else
60// elementColour = m_onlineElementColour;
61// } else
62// elementColour = m_offlineElementColour;
63//
64// if(m_inserted) {
65// std::vector<wxPoint2DDouble> arrowPts;
66// arrowPts.push_back(wxPoint2DDouble(m_position.m_x, m_position.m_y - m_height / 2.0));
67// arrowPts.push_back(arrowPts[0] + wxPoint2DDouble(0, 40));
68//
69// if(m_selected) {
70// glLineWidth(1.5 + m_borderSize * 2.0);
71// glColor4dv(m_selectionColour.GetRGBA());
72//
73// DrawLine(m_pointList);
74//
75// glPushMatrix();
76// glTranslated(m_position.m_x, m_position.m_y, 0.0);
77// glRotated(m_angle, 0.0, 0.0, 1.0);
78// glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
79//
80// DrawCircle(wxPoint2DDouble(m_position.m_x, m_position.m_y - m_height / 2.0 + 20),
81// 20.0 + (m_borderSize + 1.5) / scale, 20, GL_POLYGON);
82//
83// DrawGround(m_position + wxPoint2DDouble(0, 10.0));
84//
85// glPopMatrix();
86//
87// // Draw node selection.
88// DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
89// }
90// // Draw Harmonic current source (layer 2).
91// glLineWidth(1.5);
92// glColor4dv(elementColour.GetRGBA());
93// DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
94// DrawLine(m_pointList);
95//
96// DrawSwitches();
97//
98// glPushMatrix();
99// glTranslated(m_position.m_x, m_position.m_y, 0.0);
100// glRotated(m_angle, 0.0, 0.0, 1.0);
101// glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
102//
103// std::vector<wxPoint2DDouble> triangPts;
104// for(int i = 0; i < 3; i++) { triangPts.push_back(m_triangPts[i] + m_position); }
105//
106// glColor4dv(elementColour.GetRGBA());
107// glColor4d(1.0, 1.0, 1.0, 1.0);
108// DrawCircle(wxPoint2DDouble(m_position.m_x, m_position.m_y - m_height / 2.0 + 20), 20, 20, GL_POLYGON);
109//
110// glColor4dv(elementColour.GetRGBA());
111// DrawCircle(wxPoint2DDouble(m_position.m_x, m_position.m_y - m_height / 2.0 + 20), 20, 20);
112// DrawTriangle(triangPts);
113// DrawLine(arrowPts);
114// DrawGround(m_position + wxPoint2DDouble(0, 10.0));
115//
116// glPopMatrix();
117// }
118//}
119
120void HarmCurrent::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const
121{
122 wxColour elementColour;
123 if (m_online) {
124 if (m_dynEvent)
125 elementColour = m_dynamicEventColour;
126 else
127 elementColour = m_onlineElementColour;
128 }
129 else
130 elementColour = m_offlineElementColour;
131
132 if (m_inserted) {
133 std::vector<wxPoint2DDouble> arrowPts;
134 arrowPts.push_back(wxPoint2DDouble(m_position.m_x, m_position.m_y - m_height / 2.0));
135 arrowPts.push_back(arrowPts[0] + wxPoint2DDouble(0, 40));
136
137 // Draw Selection (layer 1).
138 if (m_selected) {
139 gc->SetPen(wxPen(wxColour(m_selectionColour), 2 + m_borderSize * 2.0));
140 gc->SetBrush(*wxTRANSPARENT_BRUSH);
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 DrawDCGround(m_position + wxPoint2DDouble(0, 10.0), gc);
151
152 gc->SetPen(*wxTRANSPARENT_PEN);
153 gc->SetBrush(wxBrush(wxColour(m_selectionColour)));
154
155 DrawDCCircle(wxPoint2DDouble(m_position.m_x, m_position.m_y - m_height / 2.0 + 20),
156 20.0 + (m_borderSize + 1.5) / scale, 20, gc);
157
158 gc->PopState();
159
160 // Draw node selection.
161 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc);
162 }
163
164 // Draw Harmonic current source (layer 2).
165 gc->SetPen(wxPen(wxColour(elementColour), 2));
166 gc->SetBrush(*wxTRANSPARENT_BRUSH);
167 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
168
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 DrawDCSwitches(gc);
175
176 std::vector<wxPoint2DDouble> triangPts;
177 for (int i = 0; i < 3; i++) { triangPts.push_back(m_triangPts[i] + m_position); }
178
179 gc->PushState();
180 gc->Translate(m_position.m_x, m_position.m_y);
181 gc->Rotate(wxDegToRad(m_angle));
182 gc->Translate(-m_position.m_x, -m_position.m_y);
183
184 //glColor4dv(elementColour);
185 gc->SetPen(wxPen(wxColour(elementColour), 2));
186 gc->SetBrush(*wxWHITE_BRUSH);
187 DrawDCCircle(wxPoint2DDouble(m_position.m_x, m_position.m_y - m_height / 2.0 + 20), 20, 20, gc);
188
189 gc->SetPen(*wxTRANSPARENT_PEN);
190 gc->SetBrush(wxBrush(wxColour(elementColour)));
191
192 DrawDCTriangle(triangPts, gc);
193
194 gc->SetPen(wxPen(wxColour(elementColour), 2));
195 gc->StrokeLines(arrowPts.size(), &arrowPts[0]);
196 DrawDCGround(m_position + wxPoint2DDouble(0, 10.0), gc);
197
198 gc->PopState();
199 }
200}
201
202void HarmCurrent::DrawDC(wxPoint2DDouble translation, double scale, wxDC& dc) const
203{
204 wxColour elementColour;
205 if (m_online) {
206 if (m_dynEvent)
207 elementColour = m_dynamicEventColour;
208 else
209 elementColour = m_onlineElementColour;
210 }
211 else
212 elementColour = m_offlineElementColour;
213
214 if (m_inserted) {
215 wxPoint arrowPts[2];
216 wxPoint2DDouble p;
217 arrowPts[0] = RotateAround(wxPoint2DDouble(m_position.m_x, m_position.m_y - m_height / 2.0), m_position, m_angle);
218 arrowPts[1] = RotateAround(wxPoint2DDouble(m_position.m_x, m_position.m_y - m_height / 2.0) + wxPoint2DDouble(0, 40), m_position, m_angle);
219
220 std::vector<wxPoint> pointListInt;
221 for (auto& pt : m_pointList) {
222 pointListInt.emplace_back(static_cast<int>(pt.m_x), static_cast<int>(pt.m_y));
223 }
224
225 // Draw Selection (layer 1).
226 if (m_selected) {
227 dc.SetPen(wxPen(wxColour(m_selectionColour), 2 + m_borderSize * 2.0));
228 dc.SetBrush(*wxTRANSPARENT_BRUSH);
229 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
230
231 DrawDCGround(m_position + wxPoint2DDouble(0, 10.0), dc);
232
233 dc.SetPen(*wxTRANSPARENT_PEN);
234 dc.SetBrush(wxBrush(wxColour(m_selectionColour)));
235
236 p = RotateAround(wxPoint2DDouble(m_position.m_x, m_position.m_y - m_height / 2.0 + 20), m_position, m_angle);
237 DrawDCCircle(p, 20.0 + (m_borderSize + 1.5) / scale, dc);
238
239 // Draw node selection.
240 DrawDCCircle(pointListInt[0], 5.0 + m_borderSize / scale, dc);
241 }
242
243 // Draw Harmonic current source (layer 2).
244 dc.SetPen(wxPen(wxColour(elementColour), 2));
245 dc.SetBrush(*wxTRANSPARENT_BRUSH);
246 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
247
248 // Draw node.
249 dc.SetPen(*wxTRANSPARENT_PEN);
250 dc.SetBrush(wxBrush(wxColour(elementColour)));
251 DrawDCCircle(pointListInt[0], 5.0, dc);
252
253 DrawDCSwitches(dc);
254
255 wxPoint triangPts[3];
256
257 //std::vector<wxPoint2DDouble> triangPts;
258 for (int i = 0; i < 3; i++) {
259 p = m_triangPts[i] + m_position;
260 triangPts[i] = RotateAround(p, m_position, m_angle);
261 }
262
263 dc.SetPen(wxPen(wxColour(elementColour), 2));
264 dc.SetBrush(*wxWHITE_BRUSH);
265 p = RotateAround(wxPoint2DDouble(m_position.m_x, m_position.m_y - m_height / 2.0 + 20), m_position, m_angle);
266 DrawDCCircle(p, 20.0, dc);
267
268 dc.SetPen(*wxTRANSPARENT_PEN);
269 dc.SetBrush(wxBrush(wxColour(elementColour)));
270 dc.DrawPolygon(3, triangPts);
271
272 dc.SetPen(wxPen(wxColour(elementColour), 2));
273 dc.DrawLines(2, arrowPts);
274 DrawDCGround(m_position + wxPoint2DDouble(0, 10.0), dc);
275 }
276}
277
278bool HarmCurrent::Contains(wxPoint2DDouble position) const
279{
280 wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
281 return m_rect.Contains(ptR);
282}
283
284bool HarmCurrent::Intersects(wxRect2DDouble rect) const
285{
286 return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0);
287}
288
289void HarmCurrent::Rotate(bool clockwise)
290{
291 double rotAngle = m_rotationAngle;
292 if (!clockwise) rotAngle = -m_rotationAngle;
293
294 m_angle += rotAngle;
295 if (m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
296 m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
297 m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
298 UpdateSwitchesPosition();
299}
300
302{
303 menu.Append(ID_EDIT_ELEMENT, _("Edit Harmonic Current Source"));
304 GeneralMenuItens(menu);
305 return true;
306}
307
309{
310 wxString tipText = m_electricalData.name;
311
312 for (unsigned int i = 0; i < m_electricalData.harmonicOrder.size(); ++i) {
313 tipText +=
314 wxString::Format("\nI%dh = %s %s (%s%s)", m_electricalData.harmonicOrder[i],
315 StringFromDouble(m_electricalData.injHarmCurrent[i]),
316 m_electricalData.injHarmCurrentUnit[i] == ElectricalUnit::UNIT_A ? "A" : "p.u.",
317 StringFromDouble(m_electricalData.injHarmAngle[i]), static_cast<wxString>(L'\u00B0'));
318 }
319
320 return tipText;
321}
322
323bool HarmCurrent::ShowForm(wxWindow* parent, Element* element)
324{
325 HarmCurrentForm harmCurrentForm(parent, this);
326 harmCurrentForm.SetTitle(_("Harmonic Current Source"));
327 harmCurrentForm.CenterOnParent();
328 if (harmCurrentForm.ShowModal() == wxID_OK) {
329 return true;
330 }
331 return false;
332}
333
334HarmCurrentElectricalData HarmCurrent::GetPUElectricalData(double systemPowerBase, double voltage)
335{
336 HarmCurrentElectricalData puData = m_electricalData;
337 double ib = systemPowerBase / (std::sqrt(3.00) * voltage);
338 for (unsigned int i = 0; i < puData.harmonicOrder.size(); ++i) {
339 if (puData.injHarmCurrentUnit[i] == ElectricalUnit::UNIT_A) {
340 puData.injHarmCurrent[i] /= ib;
341 puData.injHarmCurrentUnit[i] = ElectricalUnit::UNIT_PU;
342 }
343 }
344 return puData;
345}
346
347rapidxml::xml_node<>* HarmCurrent::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
348{
349 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "HarmCurrent");
350 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
351
352 SaveCADProperties(doc, elementNode);
353
354 auto electricalProp = XMLParser::AppendNode(doc, elementNode, "ElectricalProperties");
355 auto isOnline = XMLParser::AppendNode(doc, electricalProp, "IsOnline");
356 XMLParser::SetNodeValue(doc, isOnline, m_online);
357 auto name = XMLParser::AppendNode(doc, electricalProp, "Name");
358 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
359
360 auto harmCurrentDataList = XMLParser::AppendNode(doc, electricalProp, "HarmCurrentList");
361 for (int i = 0; i < static_cast<int>(m_electricalData.harmonicOrder.size()); i++) {
362 auto harmCurrentData = XMLParser::AppendNode(doc, harmCurrentDataList, "HarmCurrent");
363 XMLParser::SetNodeAttribute(doc, harmCurrentData, "ID", i);
364 auto order = XMLParser::AppendNode(doc, harmCurrentData, "Order");
365 XMLParser::SetNodeValue(doc, order, m_electricalData.harmonicOrder[i]);
366 auto injCurrent = XMLParser::AppendNode(doc, harmCurrentData, "InjCurrent");
367 XMLParser::SetNodeValue(doc, injCurrent, m_electricalData.injHarmCurrent[i]);
368 XMLParser::SetNodeAttribute(doc, injCurrent, "UnitID", static_cast<int>(m_electricalData.injHarmCurrentUnit[i]));
369 auto injHarmAngle = XMLParser::AppendNode(doc, harmCurrentData, "Angle");
370 XMLParser::SetNodeValue(doc, injHarmAngle, m_electricalData.injHarmAngle[i]);
371 }
372
373 return elementNode;
374}
375
376bool HarmCurrent::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
377{
378 if (!OpenCADProperties(elementNode, parentList)) return false;
379
380 auto electricalProp = elementNode->first_node("ElectricalProperties");
381 if (!electricalProp) return false;
382
383 SetOnline(XMLParser::GetNodeValueInt(electricalProp, "IsOnline"));
384 m_electricalData.name = electricalProp->first_node("Name")->value();
385
386 auto harmCurrentList = electricalProp->first_node("HarmCurrentList");
387 auto harmCurrent = harmCurrentList->first_node("HarmCurrent");
388 while (harmCurrent) {
389 m_electricalData.harmonicOrder.push_back(XMLParser::GetNodeValueInt(harmCurrent, "Order"));
390 m_electricalData.injHarmCurrent.push_back(XMLParser::GetNodeValueDouble(harmCurrent, "InjCurrent"));
391 m_electricalData.injHarmCurrentUnit.push_back(
392 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(harmCurrent, "InjCurrent", "UnitID")));
393 m_electricalData.injHarmAngle.push_back(XMLParser::GetNodeValueDouble(harmCurrent, "Angle"));
394 harmCurrent = harmCurrent->next_sibling("HarmCurrent");
395 }
396
397 m_inserted = true;
398 return true;
399}
@ ID_EDIT_ELEMENT
Definition Element.h:75
ElectricalUnit
Electrical units.
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 void DrawDCTriangle(std::vector< wxPoint2DDouble > points, wxGraphicsContext *gc) const
Draw rectangle.
Definition Element.cpp:237
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
static wxString StringFromDouble(double value, int minDecimal=1, int maxDecimals=13)
Convert a double value to string.
Definition Element.cpp:533
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
Shunt Harmonic Corrent Source.
Definition HarmCurrent.h:24
virtual wxString GetTipText() const
Get the tip text.
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element's rect intersects other rect.
virtual Element * GetCopy()
Get a the element copy.
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
virtual void Rotate(bool clockwise=true)
Rotate the element.
virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
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,...
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.
Abstract class for shunt power elements.
Definition Shunt.h:32