Power System Platform  2026w10a-beta
Loading...
Searching...
No Matches
IOControl.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 "IOControl.h"
19#include "../../forms/IOControlForm.h"
20#include <wx/dcscreen.h>
21
22IOControl::IOControl(int ioFlags, int id) : ControlElement(id)
23{
24 m_ioFlags = ioFlags;
25
26 Node* node = new Node(m_position, Node::NodeType::NODE_IN, m_borderSize);
27 m_nodeList.push_back(node);
28
29 if (ioFlags & IN_TERMINAL_VOLTAGE)
30 SetValue(IN_TERMINAL_VOLTAGE);
31 else if (ioFlags & IN_VELOCITY)
32 SetValue(IN_VELOCITY);
33 node->StartMove(m_position);
34}
35
36IOControl::~IOControl()
37{
38 //if(m_glText) delete m_glText;
39 if (m_gcText) delete m_gcText;
40 for (auto& node : m_nodeList) if (node) delete node;
41 m_nodeList.clear();
42}
43
44//void IOControl::Draw(wxPoint2DDouble translation, double scale) const
45//{
46// std::vector<wxPoint2DDouble> pts;
47// if(m_angle == 0.0) {
48// pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize));
49// pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize - 10, m_borderSize));
50// pts.push_back(m_position + wxPoint2DDouble(m_width / 2 - m_borderSize, 0));
51// pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize - 10, -m_borderSize));
52// pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize));
53// } else if(m_angle == 90.0) {
54// pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize));
55// pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize));
56// pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize - 10));
57// pts.push_back(m_position + wxPoint2DDouble(0, m_height / 2 - m_borderSize));
58// pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize - 10));
59// } else if(m_angle == 180.0) {
60// pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize + 10, m_borderSize));
61// pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize));
62// pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize));
63// pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize + 10, -m_borderSize));
64// pts.push_back(m_position + wxPoint2DDouble(-m_width / 2 + m_borderSize, 0));
65// } else if(m_angle == 270.0) {
66// pts.push_back(m_position + wxPoint2DDouble(0, -m_height / 2 + m_borderSize));
67// pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize + 10));
68// pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize));
69// pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize));
70// pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize + 10));
71// }
72//
73// if(m_selected) {
74// glColor4dv(m_selectionColour.GetRGBA());
75// double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
76// std::vector<wxPoint2DDouble> selPts = pts;
77// if(m_angle == 0.0) {
78// selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
79// selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
80// selPts[2] += wxPoint2DDouble(1.5 * borderSize / 2, 0);
81// selPts[3] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
82// selPts[4] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
83// } else if(m_angle == 90.0) {
84// selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
85// selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
86// selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
87// selPts[3] += wxPoint2DDouble(0, 1.5 * borderSize / 2);
88// selPts[4] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
89// } else if(m_angle == 180.0) {
90// selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
91// selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
92// selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
93// selPts[3] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
94// selPts[4] += wxPoint2DDouble(-1.5 * borderSize / 2, 0);
95// } else if(m_angle == 270.0) {
96// selPts[0] += wxPoint2DDouble(0, -1.5 * borderSize / 2);
97// selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
98// selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
99// selPts[3] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
100// selPts[4] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
101// }
102// DrawLine(selPts, GL_POLYGON);
103// }
104// glLineWidth(1.0);
105// glColor4d(1.0, 1.0, 1.0, 1.0);
106// DrawLine(pts, GL_POLYGON);
107// glColor4d(0.0, 0.0, 0.0, 1.0);
108// DrawLine(pts, GL_LINE_LOOP);
109//
110// // Plot number.
111// glColor4d(0.0, 0.0, 0.0, 1.0);
112// if(m_angle == 0.0) {
113// m_glText->Draw(m_position + wxPoint2DDouble(-5.0, 0.0));
114// } else if(m_angle == 90.0) {
115// m_glText->Draw(m_position + wxPoint2DDouble(0.0, -5.0));
116// } else if(m_angle == 180.0) {
117// m_glText->Draw(m_position + wxPoint2DDouble(5.0, 0.0));
118// } else if(m_angle == 270.0) {
119// m_glText->Draw(m_position + wxPoint2DDouble(0.0, 5.0));
120// }
121//
122// glColor4d(0.0, 0.0, 0.0, 1.0);
123// DrawNodes();
124//}
125
126void IOControl::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const
127{
128 std::vector<wxPoint2DDouble> pts;
129 if (m_angle == 0.0) {
130 pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize));
131 pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize - 10, m_borderSize));
132 pts.push_back(m_position + wxPoint2DDouble(m_width / 2 - m_borderSize, 0));
133 pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize - 10, -m_borderSize));
134 pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize));
135 }
136 else if (m_angle == 90.0) {
137 pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize));
138 pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize));
139 pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize - 10));
140 pts.push_back(m_position + wxPoint2DDouble(0, m_height / 2 - m_borderSize));
141 pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize - 10));
142 }
143 else if (m_angle == 180.0) {
144 pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize + 10, m_borderSize));
145 pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize));
146 pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize));
147 pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize + 10, -m_borderSize));
148 pts.push_back(m_position + wxPoint2DDouble(-m_width / 2 + m_borderSize, 0));
149 }
150 else if (m_angle == 270.0) {
151 pts.push_back(m_position + wxPoint2DDouble(0, -m_height / 2 + m_borderSize));
152 pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize + 10));
153 pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize));
154 pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize));
155 pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize + 10));
156 }
157 pts.emplace_back(pts[0]);
158
159 if (m_selected) {
160 gc->SetPen(*wxTRANSPARENT_PEN);
161 gc->SetBrush(wxBrush(m_selectionColour));
162 double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
163 std::vector<wxPoint2DDouble> selPts = pts;
164 if (m_angle == 0.0) {
165 selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
166 selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
167 selPts[2] += wxPoint2DDouble(1.5 * borderSize / 2, 0);
168 selPts[3] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
169 selPts[4] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
170 }
171 else if (m_angle == 90.0) {
172 selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
173 selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
174 selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
175 selPts[3] += wxPoint2DDouble(0, 1.5 * borderSize / 2);
176 selPts[4] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
177 }
178 else if (m_angle == 180.0) {
179 selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
180 selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
181 selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
182 selPts[3] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
183 selPts[4] += wxPoint2DDouble(-1.5 * borderSize / 2, 0);
184 }
185 else if (m_angle == 270.0) {
186 selPts[0] += wxPoint2DDouble(0, -1.5 * borderSize / 2);
187 selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
188 selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
189 selPts[3] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
190 selPts[4] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
191 }
192 gc->DrawLines(5, &selPts[0]);
193 }
194 gc->SetPen(wxPen(wxColour(0, 0, 0, 255), 1));
195 gc->SetBrush(wxBrush(wxColour(255, 255, 255, 255)));
196 gc->DrawLines(6, &pts[0]);
197
198 // Plot number.
199 if (m_angle == 0.0) {
200 m_gcText->Draw(m_position + wxPoint2DDouble(-5.0 - m_gcText->GetWidth() / 2, -m_gcText->GetHeight() / 2), gc);
201 }
202 else if (m_angle == 90.0) {
203 m_gcText->Draw(m_position + wxPoint2DDouble(-m_gcText->GetWidth() / 2, -5.0 - m_gcText->GetHeight() / 2), gc);
204 }
205 else if (m_angle == 180.0) {
206 m_gcText->Draw(m_position + wxPoint2DDouble(5.0 - m_gcText->GetWidth() / 2, -m_gcText->GetHeight() / 2), gc);
207 }
208 else if (m_angle == 270.0) {
209 m_gcText->Draw(m_position + wxPoint2DDouble(-m_gcText->GetWidth() / 2, 5.0 - m_gcText->GetHeight() / 2), gc);
210 }
211
212 gc->SetPen(*wxTRANSPARENT_PEN);
213 gc->SetBrush(wxBrush(wxColour(0, 0, 0, 255)));
214 DrawDCNodes(gc);
215}
216
217bool IOControl::ShowForm(wxWindow* parent, Element* element)
218{
219 IOControlForm form(parent, this);
220 if (form.ShowModal() == wxID_OK) {
221 return true;
222 }
223 return false;
224}
225
226void IOControl::Rotate(bool clockwise)
227{
228 if (clockwise)
229 m_angle += 90.0;
230 else
231 m_angle -= 90.0;
232 if (m_angle >= 360.0)
233 m_angle = 0.0;
234 else if (m_angle < 0)
235 m_angle = 270.0;
236
237 UpdatePoints();
238
239 for (auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
240 Node* node = *it;
241 node->Rotate(clockwise);
242 }
243}
244
245wxString IOControl::GenerateText()
246{
247 wxString omega = wxString::FromUTF8("\xCF\x89");
248 wxString subZero = wxString::FromUTF8("\xE2\x82\x92");
249 wxString capDelta = wxString::FromUTF8("\xCE\x94");
250
251 switch (m_value) {
252 case IN_TERMINAL_VOLTAGE: {
253 m_ioNodeType = Node::NodeType::NODE_OUT;
254 return _("Vt");
255 } break;
256 case IN_VELOCITY: {
257 m_ioNodeType = Node::NodeType::NODE_OUT;
258 return omega;
259 } break;
260 case IN_ACTIVE_POWER: {
261 m_ioNodeType = Node::NodeType::NODE_OUT;
262 return _("P");
263 } break;
264 case IN_REACTIVE_POWER: {
265 m_ioNodeType = Node::NodeType::NODE_OUT;
266 return _("Q");
267 } break;
268 case OUT_FIELD_VOLTAGE: {
269 m_ioNodeType = Node::NodeType::NODE_IN;
270 return _("Vf");
271 } break;
272 case OUT_MEC_POWER: {
273 m_ioNodeType = Node::NodeType::NODE_IN;
274 return _("Pm");
275 } break;
276 case IN_INITIAL_TERMINAL_VOLTAGE: {
277 m_ioNodeType = Node::NodeType::NODE_OUT;
278 return _("Vt") + subZero;
279 } break;
280 case IN_INITIAL_MEC_POWER: {
281 m_ioNodeType = Node::NodeType::NODE_OUT;
282 return _("Pm") + subZero;
283 } break;
284 case IN_INITIAL_VELOCITY: {
285 m_ioNodeType = Node::NodeType::NODE_OUT;
286 return omega + subZero;
287 } break;
288 case IN_DELTA_VELOCITY: {
289 m_ioNodeType = Node::NodeType::NODE_OUT;
290 return capDelta + omega;
291 } break;
292 case IN_DELTA_ACTIVE_POWER: {
293 m_ioNodeType = Node::NodeType::NODE_OUT;
294 return capDelta + _("P");
295 } break;
296 }
297 return "";
298}
299
300void IOControl::SetValue(IOFlags value)
301{
302 m_value = value;
303 wxString text = GenerateText();
304
305 if (m_gcText)
306 m_gcText->SetText(text);
307 else
308 m_gcText = new GCText(text);
309
310 m_width = m_gcText->GetWidth() + 10 + 2 * m_borderSize;
311 m_height = m_gcText->GetHeight() + 10 + 2 * m_borderSize;
312
313 SetPosition(m_position); // Update rectangle.
314
315 UpdatePoints();
316}
317
318void IOControl::UpdatePoints()
319{
320 if (m_nodeList.size() != 0) {
321 Node* node = m_nodeList[0];
322 if (node->GetNodeType() != m_ioNodeType) {
323 // Rotate 180 degrees
324 node->Rotate();
325 node->Rotate();
326 }
327 node->SetNodeType(m_ioNodeType);
328 if (m_angle == 0.0) {
329 if (m_ioNodeType == Node::NodeType::NODE_IN)
330 node->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
331 else
332 node->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 2, 0));
333 }
334 else if (m_angle == 90.0) {
335 if (m_ioNodeType == Node::NodeType::NODE_IN)
336 node->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
337 else
338 node->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2 - 2));
339 }
340 else if (m_angle == 180.0) {
341 if (m_ioNodeType == Node::NodeType::NODE_IN)
342 node->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
343 else
344 node->SetPosition(m_position + wxPoint2DDouble(2 - m_width / 2, 0));
345 }
346 else if (m_angle == 270.0) {
347 if (m_ioNodeType == Node::NodeType::NODE_IN)
348 node->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
349 else
350 node->SetPosition(m_position + wxPoint2DDouble(0, 2 - m_height / 2));
351 }
352 }
353}
354
356{
357 IOControl* copy = new IOControl(m_ioFlags, m_elementID);
358 *copy = *this;
359 copy->m_gcText = m_gcText->GetCopy();
360 return copy;
361}
362
364{
365 SetValue(m_value);
366 //if (!m_glText->IsTextureOK()) return false;
367 return true;
368}
369
370rapidxml::xml_node<>* IOControl::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
371{
372 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "IO");
373 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
374
375 SaveCADProperties(doc, elementNode);
376 SaveControlNodes(doc, elementNode);
377
378 // Element properties
379 auto name = XMLParser::AppendNode(doc, elementNode, "Name");
380 XMLParser::SetNodeValue(doc, name, m_name);
381 auto value = XMLParser::AppendNode(doc, elementNode, "Value");
382 XMLParser::SetNodeValue(doc, value, m_value);
383 auto ioFlags = XMLParser::AppendNode(doc, elementNode, "IOFlags");
384 XMLParser::SetNodeValue(doc, ioFlags, m_ioFlags);
385
386 return elementNode;
387}
388
389bool IOControl::OpenElement(rapidxml::xml_node<>* elementNode)
390{
391 if (!OpenCADProperties(elementNode)) return false;
392 if (!OpenControlNodes(elementNode)) return false;
393
394 // Element properties
395 IOControl::IOFlags value = static_cast<IOControl::IOFlags>(XMLParser::GetNodeValueInt(elementNode, "Value"));
396 SetValue(value);
397 auto name = elementNode->first_node("Name");
398 if (name) m_name = name->value();
399
400 return true;
401}
402
403bool IOControl::Initialize()
404{
405 m_solved = false;
406 m_output = 0.0;
407 if(m_value == IOControl::IN_TEST) {
408 m_output = m_testValue;
409 }
410 return true;
411}
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition Element.h:112
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
Definition Element.cpp:27
Class to draw text on Graphics Context using wxWidgets.
Definition GCText.h:32
virtual GCText * GetCopy()
Get a deep text copy.
Definition GCText.cpp:161
virtual void Draw(wxPoint2DDouble position, wxGraphicsContext *gc, double angle=0.0, wxColour colour= *wxBLACK) const
Draw the text in wxGraphicsContext.
Definition GCText.cpp:35
virtual void SetText(wxString text)
Set correctly a new text string.
Definition GCText.cpp:68
Form to edit the input/output control data.
Provides the communication with the power element.
Definition IOControl.h:43
virtual bool UpdateText()
Update the OpenGL text in the element (if present).
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 void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
Node of a control element. This class manages the user interaction with the connection and control el...