20#include "../../forms/SumForm.h"
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);
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);
46 for (
auto& node : m_nodeList) if (node) delete node;
119void Sum::DrawDC(wxPoint2DDouble translation,
double scale, wxGraphicsContext* gc)
const
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);
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);
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);
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);
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);
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);
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);
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);
187 gc->SetPen(*wxTRANSPARENT_PEN);
188 gc->SetBrush(*wxBLACK_BRUSH);
195 sumForm.CenterOnParent();
196 if (sumForm.ShowModal() == wxID_OK) {
202void Sum::UpdatePoints()
204 if (m_angle == 0.0 || m_angle == 180.0) {
205 m_height = 18.0 * (m_nodeList.size() - 1);
209 m_width = 18.0 * (m_nodeList.size() - 1);
213 for (
int i = 0; i < (int)m_nodeList.size() - 1; ++i) {
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));
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));
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);
242void Sum::RemoveInNode()
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) {
248 auto childNodeList = child->GetNodeList();
249 for (
auto itN = childNodeList.begin(), itEndN = childNodeList.end(); itN != itEndN; ++itN) {
251 if (node == nodeToRemove) {
258 if (foundChild)
break;
260 m_nodeList.erase(m_nodeList.end() - 2);
269 if (m_angle >= 360.0)
271 else if (m_angle < 0)
276 for (
auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
278 node->Rotate(clockwise);
282bool Sum::Solve(
double* input,
double timeStep)
288 std::vector<double> inputVector;
289 for (
auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) {
291 if (node->GetNodeType() != Node::NodeType::NODE_OUT) {
292 if (!node->IsConnected()) {
293 inputVector.push_back(0.0);
296 for (
auto itC = m_childList.begin(), itCEnd = m_childList.end(); itC != itCEnd; ++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());
311 if (m_signalList.size() != inputVector.size())
return false;
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];
325 Sum* copy =
new Sum(*
this);
329rapidxml::xml_node<>* Sum::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
331 auto elementNode = XMLParser::AppendNode(doc, elementListNode,
"Sum");
332 XMLParser::SetNodeAttribute(doc, elementNode,
"ID", m_elementID);
334 SaveCADProperties(doc, elementNode);
335 SaveControlNodes(doc, elementNode);
338 auto signsNode = XMLParser::AppendNode(doc, elementNode,
"Signs");
339 for (
unsigned int i = 0; i < m_signalList.size(); ++i) {
340 auto value = XMLParser::AppendNode(doc, signsNode,
"Value");
341 XMLParser::SetNodeValue(doc, value,
static_cast<int>(m_signalList[i]));
347bool Sum::OpenElement(rapidxml::xml_node<>* elementNode)
349 if (!OpenCADProperties(elementNode))
return false;
350 if (!OpenControlNodes(elementNode))
return false;
352 m_signalList.clear();
353 auto signsNode = elementNode->first_node(
"Signs");
354 auto sign = signsNode->first_node(
"Value");
357 wxString(sign->value()).ToCLong(&value);
358 m_signalList.push_back(
static_cast<Sum::Signal
>(value));
359 sign = sign->next_sibling(
"Value");
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...
virtual void RemoveChild(Element *child)
Remove a child from the list.
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
virtual void RemoveParent(Element *parent)
Remove a parent.
Node of a control element. This class manages the user interaction with the connection and control el...
Sum the all inputs (can choose the input signal).
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(wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
virtual void Rotate(bool clockwise=true)
Rotate the element.