Power System Platform  2026w23a-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
50void Sum::DrawDC(GUIColour* guiColour, wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const
51{
52 if (m_selected) {
53 gc->SetPen(*wxTRANSPARENT_PEN);
54 gc->SetBrush(wxBrush(guiColour->selection));
55 double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
56 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);
57 }
58 gc->SetPen(wxPen(guiColour->enabled));
59 gc->SetBrush(wxBrush(guiColour->background));
60 gc->DrawRectangle(m_position.m_x - m_width / 2, m_position.m_y - m_height / 2, m_width, m_height);
61
62 // Plot signals.
63 gc->SetPen(wxPen(guiColour->enabled, 2));
64 gc->SetBrush(*wxTRANSPARENT_BRUSH);
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 }
74 else if (m_angle == 90.0) {
75 signalOffset[0] = wxPoint2DDouble(-3, 9);
76 signalOffset[1] = wxPoint2DDouble(3, 9);
77 signalOffset[2] = wxPoint2DDouble(0, 6);
78 signalOffset[3] = wxPoint2DDouble(0, 12);
79 sigmaOffset = wxPoint2DDouble(0, 6);
80 }
81 else if (m_angle == 180.0) {
82 signalOffset[0] = wxPoint2DDouble(-6, 0);
83 signalOffset[1] = wxPoint2DDouble(-12, 0);
84 signalOffset[2] = wxPoint2DDouble(-9, -3);
85 signalOffset[3] = wxPoint2DDouble(-9, 3);
86 sigmaOffset = wxPoint2DDouble(-6, 0);
87 }
88 else if (m_angle == 270.0) {
89 signalOffset[0] = wxPoint2DDouble(-3, -9);
90 signalOffset[1] = wxPoint2DDouble(3, -9);
91 signalOffset[2] = wxPoint2DDouble(0, -6);
92 signalOffset[3] = wxPoint2DDouble(0, -12);
93 sigmaOffset = wxPoint2DDouble(0, -6);
94 }
95 for (unsigned int i = 0; i < m_nodeList.size() - 1; ++i) {
96 wxPoint2DDouble hLine[2];
97 hLine[0] = m_nodeList[i]->GetPosition() + signalOffset[0];
98 hLine[1] = m_nodeList[i]->GetPosition() + signalOffset[1];
99 gc->StrokeLines(2, hLine);
100 if (m_signalList[i] == SIGNAL_POSITIVE) {
101 wxPoint2DDouble vLine[2];
102 vLine[0] = m_nodeList[i]->GetPosition() + signalOffset[2];
103 vLine[1] = m_nodeList[i]->GetPosition() + signalOffset[3];
104 gc->StrokeLines(2, vLine);
105 }
106 }
107
108 // Plot sigma.
109 gc->SetPen(wxPen(guiColour->bus, 2));
110 wxPoint2DDouble sigma[5];
111 sigma[0] = m_position + wxPoint2DDouble(4, 9) + sigmaOffset;
112 sigma[1] = m_position + wxPoint2DDouble(-6, 9) + sigmaOffset;
113 sigma[2] = m_position + wxPoint2DDouble(0, 0) + sigmaOffset;
114 sigma[3] = m_position + wxPoint2DDouble(-6, -9) + sigmaOffset;
115 sigma[4] = m_position + wxPoint2DDouble(4, -9) + sigmaOffset;
116 gc->StrokeLines(5, sigma);
117
118 gc->SetPen(*wxTRANSPARENT_PEN);
119 gc->SetBrush(wxBrush(guiColour->enabled));
120 DrawDCNodes(gc);
121}
122
123bool Sum::ShowForm(wxWindow* parent, Element* element, wxWindow* workspace)
124{
125 SumForm sumForm(parent, this);
126 sumForm.CenterOnParent();
127 if (sumForm.ShowModal() == wxID_OK) {
128 return true;
129 }
130 return false;
131}
132
133void Sum::UpdatePoints()
134{
135 if (m_angle == 0.0 || m_angle == 180.0) {
136 m_height = 18.0 * (m_nodeList.size() - 1);
137 m_width = 36.0;
138 }
139 else {
140 m_width = 18.0 * (m_nodeList.size() - 1);
141 m_height = 42.0;
142 }
143
144 for (int i = 0; i < (int)m_nodeList.size() - 1; ++i) {
145 if (m_angle == 0.0)
146 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 9 + 18 * i - m_height / 2));
147 else if (m_angle == 90.0)
148 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 9 - 18 * i, -m_height / 2));
149 else if (m_angle == 180.0)
150 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, m_height / 2 - 9 - 18 * i));
151 else if (m_angle == 270.0)
152 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(9 + 18 * i - m_width / 2, m_height / 2));
153 }
154 if (m_angle == 0.0)
155 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
156 else if (m_angle == 90.0)
157 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
158 else if (m_angle == 180.0)
159 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
160 else if (m_angle == 270.0)
161 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
162
163 SetPosition(m_position); // Update rect.
164}
165
166void Sum::AddInNode()
167{
168 Node* newNode = new Node(wxPoint2DDouble(0, 0), Node::NodeType::NODE_IN, m_borderSize);
169 newNode->SetAngle(m_angle);
170 m_nodeList.insert(m_nodeList.end() - 1, newNode);
171}
172
173void Sum::RemoveInNode()
174{
175 Node* nodeToRemove = *(m_nodeList.end() - 2);
176 bool foundChild = false;
177 for (auto it = m_childList.begin(), itEnd = m_childList.end(); it != itEnd; ++it) {
178 ControlElement* child = static_cast<ControlElement*>(*it);
179 auto childNodeList = child->GetNodeList();
180 for (auto itN = childNodeList.begin(), itEndN = childNodeList.end(); itN != itEndN; ++itN) {
181 Node* node = *itN;
182 if (node == nodeToRemove) {
183 child->RemoveParent(this);
184 RemoveChild(child);
185 foundChild = true;
186 break;
187 }
188 }
189 if (foundChild) break;
190 }
191 m_nodeList.erase(m_nodeList.end() - 2);
192}
193
194void Sum::Rotate(bool clockwise)
195{
196 if (clockwise)
197 m_angle += 90.0;
198 else
199 m_angle -= 90.0;
200 if (m_angle >= 360.0)
201 m_angle = 0.0;
202 else if (m_angle < 0)
203 m_angle = 270.0;
204
205 UpdatePoints();
206
207 for (auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
208 Node* node = *it;
209 node->Rotate(clockwise);
210 }
211}
212
213bool Sum::Solve(double* input, double timeStep)
214{
215 if (!input) {
216 m_output = 0.0;
217 return true;
218 }
219 std::vector<double> inputVector;
220 for (auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) {
221 Node* node = *itN;
222 if (node->GetNodeType() != Node::NodeType::NODE_OUT) {
223 if (!node->IsConnected()) {
224 inputVector.push_back(0.0);
225 }
226 else {
227 for (auto itC = m_childList.begin(), itCEnd = m_childList.end(); itC != itCEnd; ++itC) {
228 ConnectionLine* cLine = static_cast<ConnectionLine*>(*itC);
229 auto nodeList = cLine->GetNodeList();
230 for (auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
231 Node* childNode = *itCN;
232 if (childNode == node) {
233 inputVector.push_back(cLine->GetValue());
234 break;
235 }
236 }
237 }
238 }
239 }
240 }
241
242 if (m_signalList.size() != inputVector.size()) return false;
243
244 m_output = 0.0;
245 for (unsigned int i = 0; i < m_signalList.size(); ++i) {
246 if (m_signalList[i] == SIGNAL_POSITIVE)
247 m_output += inputVector[i];
248 else if (m_signalList[i] == SIGNAL_NEGATIVE)
249 m_output -= inputVector[i];
250 }
251 return true;
252}
253
255{
256 Sum* copy = new Sum(*this);
257 return copy;
258}
259
260rapidxml::xml_node<>* Sum::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
261{
262 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "Sum");
263 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
264
265 SaveCADProperties(doc, elementNode);
266 SaveControlNodes(doc, elementNode);
267
268 // Element properties
269 auto signsNode = XMLParser::AppendNode(doc, elementNode, "Signs");
270 for (unsigned int i = 0; i < m_signalList.size(); ++i) {
271 auto value = XMLParser::AppendNode(doc, signsNode, "Value");
272 XMLParser::SetNodeValue(doc, value, static_cast<int>(m_signalList[i]));
273 }
274
275 return elementNode;
276}
277
278bool Sum::OpenElement(rapidxml::xml_node<>* elementNode)
279{
280 if (!OpenCADProperties(elementNode)) return false;
281 if (!OpenControlNodes(elementNode)) return false;
282
283 m_signalList.clear();
284 auto signsNode = elementNode->first_node("Signs");
285 auto sign = signsNode->first_node("Value");
286 while (sign) {
287 long value;
288 wxString(sign->value()).ToCLong(&value);
289 m_signalList.push_back(static_cast<Sum::Signal>(value));
290 sign = sign->next_sibling("Value");
291 }
292
293 StartMove(m_position);
294 UpdatePoints();
295
296 return true;
297}
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:114
virtual void RemoveChild(Element *child)
Remove a child from the list.
Definition Element.cpp:500
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
Definition Element.cpp:33
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition Element.h:374
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 bool ShowForm(wxWindow *parent, Element *element, wxWindow *workspace=nullptr)
Show element data form.
Definition Sum.cpp:123
virtual Element * GetCopy()
Get a the element copy.
Definition Sum.cpp:254
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition Sum.cpp:194
virtual void DrawDC(GUIColour *guiColour, wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
Definition Sum.cpp:50