Power System Platform  2026w23a-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
44void IOControl::DrawDC(GUIColour* guiColour, wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) 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 }
54 else if (m_angle == 90.0) {
55 pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize));
56 pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize));
57 pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize - 10));
58 pts.push_back(m_position + wxPoint2DDouble(0, m_height / 2 - m_borderSize));
59 pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize - 10));
60 }
61 else if (m_angle == 180.0) {
62 pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize + 10, m_borderSize));
63 pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize));
64 pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize));
65 pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize + 10, -m_borderSize));
66 pts.push_back(m_position + wxPoint2DDouble(-m_width / 2 + m_borderSize, 0));
67 }
68 else if (m_angle == 270.0) {
69 pts.push_back(m_position + wxPoint2DDouble(0, -m_height / 2 + m_borderSize));
70 pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize + 10));
71 pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize));
72 pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize));
73 pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize + 10));
74 }
75 pts.emplace_back(pts[0]);
76
77 if (m_selected) {
78 gc->SetPen(*wxTRANSPARENT_PEN);
79 gc->SetBrush(wxBrush(guiColour->selection));
80 double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
81 std::vector<wxPoint2DDouble> selPts = pts;
82 if (m_angle == 0.0) {
83 selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
84 selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
85 selPts[2] += wxPoint2DDouble(1.5 * borderSize / 2, 0);
86 selPts[3] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
87 selPts[4] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
88 }
89 else if (m_angle == 90.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(0, 1.5 * borderSize / 2);
94 selPts[4] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
95 }
96 else if (m_angle == 180.0) {
97 selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
98 selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
99 selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
100 selPts[3] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
101 selPts[4] += wxPoint2DDouble(-1.5 * borderSize / 2, 0);
102 }
103 else if (m_angle == 270.0) {
104 selPts[0] += wxPoint2DDouble(0, -1.5 * borderSize / 2);
105 selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
106 selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
107 selPts[3] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
108 selPts[4] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
109 }
110 gc->DrawLines(5, &selPts[0]);
111 }
112 gc->SetPen(wxPen(guiColour->enabled, 1));
113 gc->SetBrush(guiColour->background);
114 gc->DrawLines(6, &pts[0]);
115
116 // Plot number.
117 if (m_angle == 0.0) {
118 m_gcText->Draw(m_position + wxPoint2DDouble(-5.0 - m_gcText->GetWidth() / 2, -m_gcText->GetHeight() / 2), gc, 0, guiColour->text);
119 }
120 else if (m_angle == 90.0) {
121 m_gcText->Draw(m_position + wxPoint2DDouble(-m_gcText->GetWidth() / 2, -5.0 - m_gcText->GetHeight() / 2), gc, 0, guiColour->text);
122 }
123 else if (m_angle == 180.0) {
124 m_gcText->Draw(m_position + wxPoint2DDouble(5.0 - m_gcText->GetWidth() / 2, -m_gcText->GetHeight() / 2), gc, 0, guiColour->text);
125 }
126 else if (m_angle == 270.0) {
127 m_gcText->Draw(m_position + wxPoint2DDouble(-m_gcText->GetWidth() / 2, 5.0 - m_gcText->GetHeight() / 2), gc, 0, guiColour->text);
128 }
129
130 gc->SetPen(*wxTRANSPARENT_PEN);
131 gc->SetBrush(guiColour->enabled);
132 DrawDCNodes(gc);
133}
134
135bool IOControl::ShowForm(wxWindow* parent, Element* element, wxWindow* workspace)
136{
137 IOControlForm form(parent, this);
138 if (form.ShowModal() == wxID_OK) {
139 return true;
140 }
141 return false;
142}
143
144void IOControl::Rotate(bool clockwise)
145{
146 if (clockwise)
147 m_angle += 90.0;
148 else
149 m_angle -= 90.0;
150 if (m_angle >= 360.0)
151 m_angle = 0.0;
152 else if (m_angle < 0)
153 m_angle = 270.0;
154
155 UpdatePoints();
156
157 for (auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
158 Node* node = *it;
159 node->Rotate(clockwise);
160 }
161}
162
163void IOControl::SetFont(wxFont& font)
164{
165 m_gcText->SetFont(font);
166 UpdateText();
167}
168
169wxString IOControl::GenerateText()
170{
171 wxString omega = wxString::FromUTF8("\xCF\x89");
172 wxString subZero = wxString::FromUTF8("\xE2\x82\x92");
173 wxString capDelta = wxString::FromUTF8("\xCE\x94");
174
175 switch (m_value) {
176 case IN_TERMINAL_VOLTAGE: {
177 m_ioNodeType = Node::NodeType::NODE_OUT;
178 return _("Vt");
179 } break;
180 case IN_VELOCITY: {
181 m_ioNodeType = Node::NodeType::NODE_OUT;
182 return omega;
183 } break;
184 case IN_ACTIVE_POWER: {
185 m_ioNodeType = Node::NodeType::NODE_OUT;
186 return _("P");
187 } break;
188 case IN_REACTIVE_POWER: {
189 m_ioNodeType = Node::NodeType::NODE_OUT;
190 return _("Q");
191 } break;
192 case OUT_FIELD_VOLTAGE: {
193 m_ioNodeType = Node::NodeType::NODE_IN;
194 return _("Vf");
195 } break;
196 case OUT_MEC_POWER: {
197 m_ioNodeType = Node::NodeType::NODE_IN;
198 return _("Pm");
199 } break;
200 case IN_INITIAL_TERMINAL_VOLTAGE: {
201 m_ioNodeType = Node::NodeType::NODE_OUT;
202 return _("Vt") + subZero;
203 } break;
204 case IN_INITIAL_MEC_POWER: {
205 m_ioNodeType = Node::NodeType::NODE_OUT;
206 return _("Pm") + subZero;
207 } break;
208 case IN_INITIAL_VELOCITY: {
209 m_ioNodeType = Node::NodeType::NODE_OUT;
210 return omega + subZero;
211 } break;
212 case IN_DELTA_VELOCITY: {
213 m_ioNodeType = Node::NodeType::NODE_OUT;
214 return capDelta + omega;
215 } break;
216 case IN_DELTA_ACTIVE_POWER: {
217 m_ioNodeType = Node::NodeType::NODE_OUT;
218 return capDelta + _("P");
219 } break;
220 case IN_IO: {
221 m_ioNodeType = Node::NodeType::NODE_OUT;
222 return _("I/O");
223 } break;
224 }
225 return "";
226}
227
228void IOControl::SetValue(IOFlags value)
229{
230 m_value = value;
231 wxString text = GenerateText();
232
233 if (m_gcText)
234 m_gcText->SetText(text);
235 else
236 m_gcText = new GCText(text);
237
238 m_width = m_gcText->GetWidth() + 10 + 2 * m_borderSize;
239 m_height = m_gcText->GetHeight() + 10 + 2 * m_borderSize;
240
241 SetPosition(m_position); // Update rectangle.
242
243 UpdatePoints();
244}
245
246void IOControl::UpdatePoints()
247{
248 if (m_nodeList.size() != 0) {
249 Node* node = m_nodeList[0];
250 if (node->GetNodeType() != m_ioNodeType) {
251 // Rotate 180 degrees
252 node->Rotate();
253 node->Rotate();
254 }
255 node->SetNodeType(m_ioNodeType);
256 if (m_angle == 0.0) {
257 if (m_ioNodeType == Node::NodeType::NODE_IN)
258 node->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
259 else
260 node->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 2, 0));
261 }
262 else if (m_angle == 90.0) {
263 if (m_ioNodeType == Node::NodeType::NODE_IN)
264 node->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
265 else
266 node->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2 - 2));
267 }
268 else if (m_angle == 180.0) {
269 if (m_ioNodeType == Node::NodeType::NODE_IN)
270 node->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
271 else
272 node->SetPosition(m_position + wxPoint2DDouble(2 - m_width / 2, 0));
273 }
274 else if (m_angle == 270.0) {
275 if (m_ioNodeType == Node::NodeType::NODE_IN)
276 node->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
277 else
278 node->SetPosition(m_position + wxPoint2DDouble(0, 2 - m_height / 2));
279 }
280 }
281}
282
284{
285 IOControl* copy = new IOControl(*this);
286 copy->m_gcText = m_gcText ? m_gcText->GetCopy() : nullptr;
287 return copy;
288}
289
291{
292 SetValue(m_value);
293 //if (!m_glText->IsTextureOK()) return false;
294 return true;
295}
296
297rapidxml::xml_node<>* IOControl::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
298{
299 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "IO");
300 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
301
302 SaveCADProperties(doc, elementNode);
303 SaveControlNodes(doc, elementNode);
304
305 // Element properties
306 auto name = XMLParser::AppendNode(doc, elementNode, "Name");
307 XMLParser::SetNodeValue(doc, name, m_name);
308 auto value = XMLParser::AppendNode(doc, elementNode, "Value");
309 XMLParser::SetNodeValue(doc, value, m_value);
310 auto ioFlags = XMLParser::AppendNode(doc, elementNode, "IOFlags");
311 XMLParser::SetNodeValue(doc, ioFlags, m_ioFlags);
312
313 return elementNode;
314}
315
316bool IOControl::OpenElement(rapidxml::xml_node<>* elementNode)
317{
318 if (!OpenCADProperties(elementNode)) return false;
319 if (!OpenControlNodes(elementNode)) return false;
320
321 // Element properties
322 IOControl::IOFlags value = static_cast<IOControl::IOFlags>(XMLParser::GetNodeValueInt(elementNode, "Value"));
323 SetValue(value);
324 auto name = elementNode->first_node("Name");
325 if (name) m_name = name->value();
326
327 return true;
328}
329
330bool IOControl::Initialize()
331{
332 m_solved = false;
333 m_output = 0.0;
334 if(m_value == IOControl::IN_TEST) {
335 m_output = m_testValue;
336 }
337 return true;
338}
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition Element.h:114
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
Definition Element.cpp:33
Class to draw text on Graphics Context using wxWidgets.
Definition GCText.h:32
virtual GCText * GetCopy()
Get a deep text copy.
Definition GCText.cpp:99
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 bool ShowForm(wxWindow *parent, Element *element, wxWindow *workspace=nullptr)
Show element data form.
virtual Element * GetCopy()
Get a the element copy.
virtual void DrawDC(GUIColour *guiColour, wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
Definition IOControl.cpp:44
Node of a control element. This class manages the user interaction with the connection and control el...