Power System Platform  2026w10a-beta
Loading...
Searching...
No Matches
Sum.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 "ConnectionLine.h"
19#include "Sum.h"
20#include "../../forms/SumForm.h"
21#include <wx/pen.h>
22#include <wx/brush.h>
23
24Sum::Sum(int id) : ControlElement(id)
25{
26 m_width = m_height = 36.0;
27 Node* nodeIn1 = new Node(m_position + wxPoint2DDouble(-m_width / 2, 9 - m_height / 2), Node::NodeType::NODE_IN, m_borderSize);
28 nodeIn1->StartMove(m_position);
29 Node* nodeIn2 =
30 new Node(m_position + wxPoint2DDouble(-m_width / 2, 27 - m_height / 2), Node::NodeType::NODE_IN, m_borderSize);
31 nodeIn2->StartMove(m_position);
32 Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NodeType::NODE_OUT, m_borderSize);
33 nodeOut->SetAngle(180.0);
34 nodeOut->StartMove(m_position);
35 m_nodeList.push_back(nodeIn1);
36 m_nodeList.push_back(nodeIn2);
37 m_nodeList.push_back(nodeOut);
38 m_signalList.push_back(SIGNAL_POSITIVE);
39 m_signalList.push_back(SIGNAL_NEGATIVE);
40
41 UpdatePoints();
42}
43
44Sum::~Sum()
45{
46 for (auto& node : m_nodeList) if (node) delete node;
47 m_nodeList.clear();
48}
49
50//void Sum::Draw(wxPoint2DDouble translation, double scale) const
51//{
52// glLineWidth(1.0);
53// if(m_selected) {
54// glColor4dv(m_selectionColour.GetRGBA());
55// double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
56// DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
57// }
58// glColor4d(1.0, 1.0, 1.0, 1.0);
59// DrawRectangle(m_position, m_width, m_height);
60// glColor4d(0.0, 0.0, 0.0, 1.0);
61// DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
62//
63// // Plot signals.
64// glLineWidth(2.0);
65// wxPoint2DDouble signalOffset[4];
66// wxPoint2DDouble sigmaOffset;
67// if(m_angle == 0.0) {
68// signalOffset[0] = wxPoint2DDouble(6, 0);
69// signalOffset[1] = wxPoint2DDouble(12, 0);
70// signalOffset[2] = wxPoint2DDouble(9, -3);
71// signalOffset[3] = wxPoint2DDouble(9, 3);
72// sigmaOffset = wxPoint2DDouble(6, 0);
73// } else if(m_angle == 90.0) {
74// signalOffset[0] = wxPoint2DDouble(-3, 9);
75// signalOffset[1] = wxPoint2DDouble(3, 9);
76// signalOffset[2] = wxPoint2DDouble(0, 6);
77// signalOffset[3] = wxPoint2DDouble(0, 12);
78// sigmaOffset = wxPoint2DDouble(0, 6);
79// } else if(m_angle == 180.0) {
80// signalOffset[0] = wxPoint2DDouble(-6, 0);
81// signalOffset[1] = wxPoint2DDouble(-12, 0);
82// signalOffset[2] = wxPoint2DDouble(-9, -3);
83// signalOffset[3] = wxPoint2DDouble(-9, 3);
84// sigmaOffset = wxPoint2DDouble(-6, 0);
85// } else if(m_angle == 270.0) {
86// signalOffset[0] = wxPoint2DDouble(-3, -9);
87// signalOffset[1] = wxPoint2DDouble(3, -9);
88// signalOffset[2] = wxPoint2DDouble(0, -6);
89// signalOffset[3] = wxPoint2DDouble(0, -12);
90// sigmaOffset = wxPoint2DDouble(0, -6);
91// }
92// for(int i = 0; i < (int)m_nodeList.size() - 1; ++i) {
93// std::vector<wxPoint2DDouble> hLine;
94// hLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[0]);
95// hLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[1]);
96// DrawLine(hLine);
97// if(m_signalList[i] == SIGNAL_POSITIVE) {
98// std::vector<wxPoint2DDouble> vLine;
99// vLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[2]);
100// vLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[3]);
101// DrawLine(vLine);
102// }
103// }
104//
105// // Plot sigma.
106// std::vector<wxPoint2DDouble> sigma;
107// sigma.push_back(m_position + wxPoint2DDouble(4, 9) + sigmaOffset);
108// sigma.push_back(m_position + wxPoint2DDouble(-6, 9) + sigmaOffset);
109// sigma.push_back(m_position + wxPoint2DDouble(0, 0) + sigmaOffset);
110// sigma.push_back(m_position + wxPoint2DDouble(-6, -9) + sigmaOffset);
111// sigma.push_back(m_position + wxPoint2DDouble(4, -9) + sigmaOffset);
112// glColor4d(0.0, 0.3, 1.0, 1.0);
113// DrawLine(sigma);
114//
115// glColor4d(0.0, 0.0, 0.0, 1.0);
116// DrawNodes();
117//}
118
119void Sum::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const
120{
121 if (m_selected) {
122 gc->SetPen(*wxTRANSPARENT_PEN);
123 gc->SetBrush(wxBrush(m_selectionColour));
124 double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
125 gc->DrawRectangle(m_position.m_x - m_width / 2 - borderSize / 2, m_position.m_y - m_height / 2 - borderSize / 2, m_width + borderSize, m_height + borderSize);
126 }
127 gc->SetPen(*wxBLACK_PEN);
128 gc->SetBrush(*wxWHITE_BRUSH);
129 gc->DrawRectangle(m_position.m_x - m_width / 2, m_position.m_y - m_height / 2, m_width, m_height);
130
131 // Plot signals.
132 gc->SetPen(wxPen(wxColour(0, 0, 0, 255), 2));
133 gc->SetBrush(*wxTRANSPARENT_BRUSH);
134 wxPoint2DDouble signalOffset[4];
135 wxPoint2DDouble sigmaOffset;
136 if (m_angle == 0.0) {
137 signalOffset[0] = wxPoint2DDouble(6, 0);
138 signalOffset[1] = wxPoint2DDouble(12, 0);
139 signalOffset[2] = wxPoint2DDouble(9, -3);
140 signalOffset[3] = wxPoint2DDouble(9, 3);
141 sigmaOffset = wxPoint2DDouble(6, 0);
142 }
143 else if (m_angle == 90.0) {
144 signalOffset[0] = wxPoint2DDouble(-3, 9);
145 signalOffset[1] = wxPoint2DDouble(3, 9);
146 signalOffset[2] = wxPoint2DDouble(0, 6);
147 signalOffset[3] = wxPoint2DDouble(0, 12);
148 sigmaOffset = wxPoint2DDouble(0, 6);
149 }
150 else if (m_angle == 180.0) {
151 signalOffset[0] = wxPoint2DDouble(-6, 0);
152 signalOffset[1] = wxPoint2DDouble(-12, 0);
153 signalOffset[2] = wxPoint2DDouble(-9, -3);
154 signalOffset[3] = wxPoint2DDouble(-9, 3);
155 sigmaOffset = wxPoint2DDouble(-6, 0);
156 }
157 else if (m_angle == 270.0) {
158 signalOffset[0] = wxPoint2DDouble(-3, -9);
159 signalOffset[1] = wxPoint2DDouble(3, -9);
160 signalOffset[2] = wxPoint2DDouble(0, -6);
161 signalOffset[3] = wxPoint2DDouble(0, -12);
162 sigmaOffset = wxPoint2DDouble(0, -6);
163 }
164 for (unsigned int i = 0; i < m_nodeList.size() - 1; ++i) {
165 wxPoint2DDouble hLine[2];
166 hLine[0] = m_nodeList[i]->GetPosition() + signalOffset[0];
167 hLine[1] = m_nodeList[i]->GetPosition() + signalOffset[1];
168 gc->StrokeLines(2, hLine);
169 if (m_signalList[i] == SIGNAL_POSITIVE) {
170 wxPoint2DDouble vLine[2];
171 vLine[0] = m_nodeList[i]->GetPosition() + signalOffset[2];
172 vLine[1] = m_nodeList[i]->GetPosition() + signalOffset[3];
173 gc->StrokeLines(2, vLine);
174 }
175 }
176
177 // Plot sigma.
178 gc->SetPen(wxPen(wxColour(0, 77, 255, 255), 2));
179 wxPoint2DDouble sigma[5];
180 sigma[0] = m_position + wxPoint2DDouble(4, 9) + sigmaOffset;
181 sigma[1] = m_position + wxPoint2DDouble(-6, 9) + sigmaOffset;
182 sigma[2] = m_position + wxPoint2DDouble(0, 0) + sigmaOffset;
183 sigma[3] = m_position + wxPoint2DDouble(-6, -9) + sigmaOffset;
184 sigma[4] = m_position + wxPoint2DDouble(4, -9) + sigmaOffset;
185 gc->StrokeLines(5, sigma);
186
187 gc->SetPen(*wxTRANSPARENT_PEN);
188 gc->SetBrush(*wxBLACK_BRUSH);
189 DrawDCNodes(gc);
190}
191
192bool Sum::ShowForm(wxWindow* parent, Element* element)
193{
194 SumForm sumForm(parent, this);
195 sumForm.CenterOnParent();
196 if (sumForm.ShowModal() == wxID_OK) {
197 return true;
198 }
199 return false;
200}
201
202void Sum::UpdatePoints()
203{
204 if (m_angle == 0.0 || m_angle == 180.0) {
205 m_height = 18.0 * (m_nodeList.size() - 1);
206 m_width = 36.0;
207 }
208 else {
209 m_width = 18.0 * (m_nodeList.size() - 1);
210 m_height = 42.0;
211 }
212
213 for (int i = 0; i < (int)m_nodeList.size() - 1; ++i) {
214 if (m_angle == 0.0)
215 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 9 + 18 * i - m_height / 2));
216 else if (m_angle == 90.0)
217 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 9 - 18 * i, -m_height / 2));
218 else if (m_angle == 180.0)
219 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, m_height / 2 - 9 - 18 * i));
220 else if (m_angle == 270.0)
221 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(9 + 18 * i - m_width / 2, m_height / 2));
222 }
223 if (m_angle == 0.0)
224 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
225 else if (m_angle == 90.0)
226 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
227 else if (m_angle == 180.0)
228 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
229 else if (m_angle == 270.0)
230 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
231
232 SetPosition(m_position); // Update rect.
233}
234
235void Sum::AddInNode()
236{
237 Node* newNode = new Node(wxPoint2DDouble(0, 0), Node::NodeType::NODE_IN, m_borderSize);
238 newNode->SetAngle(m_angle);
239 m_nodeList.insert(m_nodeList.end() - 1, newNode);
240}
241
242void Sum::RemoveInNode()
243{
244 Node* nodeToRemove = *(m_nodeList.end() - 2);
245 bool foundChild = false;
246 for (auto it = m_childList.begin(), itEnd = m_childList.end(); it != itEnd; ++it) {
247 ControlElement* child = static_cast<ControlElement*>(*it);
248 auto childNodeList = child->GetNodeList();
249 for (auto itN = childNodeList.begin(), itEndN = childNodeList.end(); itN != itEndN; ++itN) {
250 Node* node = *itN;
251 if (node == nodeToRemove) {
252 child->RemoveParent(this);
253 RemoveChild(child);
254 foundChild = true;
255 break;
256 }
257 }
258 if (foundChild) break;
259 }
260 m_nodeList.erase(m_nodeList.end() - 2);
261}
262
263void Sum::Rotate(bool clockwise)
264{
265 if (clockwise)
266 m_angle += 90.0;
267 else
268 m_angle -= 90.0;
269 if (m_angle >= 360.0)
270 m_angle = 0.0;
271 else if (m_angle < 0)
272 m_angle = 270.0;
273
274 UpdatePoints();
275
276 for (auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
277 Node* node = *it;
278 node->Rotate(clockwise);
279 }
280}
281
282bool Sum::Solve(double* input, double timeStep)
283{
284 if (!input) {
285 m_output = 0.0;
286 return true;
287 }
288 std::vector<double> inputVector;
289 for (auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) {
290 Node* node = *itN;
291 if (node->GetNodeType() != Node::NodeType::NODE_OUT) {
292 if (!node->IsConnected()) {
293 inputVector.push_back(0.0);
294 }
295 else {
296 for (auto itC = m_childList.begin(), itCEnd = m_childList.end(); itC != itCEnd; ++itC) {
297 ConnectionLine* cLine = static_cast<ConnectionLine*>(*itC);
298 auto nodeList = cLine->GetNodeList();
299 for (auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
300 Node* childNode = *itCN;
301 if (childNode == node) {
302 inputVector.push_back(cLine->GetValue());
303 break;
304 }
305 }
306 }
307 }
308 }
309 }
310
311 if (m_signalList.size() != inputVector.size()) return false;
312
313 m_output = 0.0;
314 for (unsigned int i = 0; i < m_signalList.size(); ++i) {
315 if (m_signalList[i] == SIGNAL_POSITIVE)
316 m_output += inputVector[i];
317 else if (m_signalList[i] == SIGNAL_NEGATIVE)
318 m_output -= inputVector[i];
319 }
320 return true;
321}
322
324{
325 Sum* copy = new Sum(m_elementID);
326 *copy = *this;
327 return copy;
328}
329
330rapidxml::xml_node<>* Sum::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
331{
332 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "Sum");
333 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
334
335 SaveCADProperties(doc, elementNode);
336 SaveControlNodes(doc, elementNode);
337
338 // Element properties
339 auto signsNode = XMLParser::AppendNode(doc, elementNode, "Signs");
340 for (unsigned int i = 0; i < m_signalList.size(); ++i) {
341 auto value = XMLParser::AppendNode(doc, signsNode, "Value");
342 XMLParser::SetNodeValue(doc, value, static_cast<int>(m_signalList[i]));
343 }
344
345 return elementNode;
346}
347
348bool Sum::OpenElement(rapidxml::xml_node<>* elementNode)
349{
350 if (!OpenCADProperties(elementNode)) return false;
351 if (!OpenControlNodes(elementNode)) return false;
352
353 m_signalList.clear();
354 auto signsNode = elementNode->first_node("Signs");
355 auto sign = signsNode->first_node("Value");
356 while (sign) {
357 long value;
358 wxString(sign->value()).ToCLong(&value);
359 m_signalList.push_back(static_cast<Sum::Signal>(value));
360 sign = sign->next_sibling("Value");
361 }
362
363 StartMove(m_position);
364 UpdatePoints();
365
366 return true;
367}
Connection between two control elements or other connection line and an element.
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition Element.h:112
virtual void RemoveChild(Element *child)
Remove a child from the list.
Definition Element.cpp:567
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
Definition Element.cpp:27
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition Element.h:371
Node of a control element. This class manages the user interaction with the connection and control el...
Form to edit the sum control data.
Definition SumForm.h:33
Sum the all inputs (can choose the input signal).
Definition Sum.h:34
virtual Element * GetCopy()
Get a the element copy.
Definition Sum.cpp:323
virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
Definition Sum.cpp:119
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition Sum.cpp:263
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition Sum.cpp:192