20#include "../../forms/MathExpressionForm.h"
26 m_variablesVector.push_back(
"x");
27 m_variablesVector.push_back(
"y");
29 for (
unsigned int i = 0; i < m_variablesVector.size(); ++i) {
30 m_gcTextInputVector.push_back(
new GCText(m_variablesVector[i]));
34 m_symbol.SetFont(wxFont(12, wxFONTFAMILY_ROMAN, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_BOLD));
35 m_symbol.SetText(
"f(x)");
36 m_symbolSize = wxSize(m_symbol.GetWidth(), m_symbol.GetHeight());
38 CalculateBlockSize(
static_cast<double>(m_variablesVector.size()));
40 for (
unsigned int i = 0; i < m_variablesVector.size(); ++i) {
41 wxPoint2DDouble nodePosition(0, 0);
42 if (m_variablesVector.size() == 1) {
43 nodePosition = m_position + wxPoint2DDouble(-m_width / 2, 0);
46 nodePosition = m_position + wxPoint2DDouble(-m_width / 2, 9 + 18 * i - m_height / 2);
48 Node* nodeIn =
new Node(nodePosition, Node::NodeType::NODE_IN, m_borderSize);
49 nodeIn->StartMove(m_position);
50 m_nodeList.push_back(nodeIn);
52 Node* nodeOut =
new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NodeType::NODE_OUT, m_borderSize);
53 nodeOut->SetAngle(180.0);
54 nodeOut->StartMove(m_position);
55 m_nodeList.push_back(nodeOut);
60MathExpression::~MathExpression()
62 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
delete* it; }
63 m_gcTextInputVector.clear();
64 for (
auto& node : m_nodeList) if (node) delete node;
71 double pi = 3.1415926535897932;
73 gc->SetPen(*wxTRANSPARENT_PEN);
74 gc->SetBrush(guiColour->selection);
75 double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
76 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);
78 gc->SetPen(wxPen(guiColour->enabled, 1));
79 gc->SetBrush(guiColour->background);
80 gc->DrawRectangle(m_position.m_x - m_width / 2, m_position.m_y - m_height / 2, m_width, m_height);
84 double w =
static_cast<double>(m_symbolSize.GetWidth());
85 double h =
static_cast<double>(m_symbolSize.GetHeight());
86 m_symbol.
Draw(m_nodeList[m_nodeList.size() - 1]->GetPosition() - wxPoint2DDouble(w + 6.0, h / 2.0), gc, 0, guiColour->bus);
87 for (
unsigned int i = 0; i < m_gcTextInputVector.size(); ++i) {
88 w =
static_cast<double>(m_gcTextInputVector[i]->GetWidth());
89 h =
static_cast<double>(m_gcTextInputVector[i]->GetHeight());
90 m_gcTextInputVector[i]->Draw(m_nodeList[i]->
GetPosition() + wxPoint2DDouble(6.0, -h / 2.0), gc, 0, guiColour->enabled);
93 else if (m_angle == 90.0) {
94 double w =
static_cast<double>(m_symbolSize.GetWidth());
95 double h =
static_cast<double>(m_symbolSize.GetHeight());
96 m_symbol.
Draw(m_nodeList[m_nodeList.size() - 1]->GetPosition() - wxPoint2DDouble(w / 2, h + 6.0), gc, 0, guiColour->bus);
97 for (
unsigned int i = 0; i < m_gcTextInputVector.size(); ++i) {
98 w =
static_cast<double>(m_gcTextInputVector[i]->GetWidth());
99 h =
static_cast<double>(m_gcTextInputVector[i]->GetHeight());
100 m_gcTextInputVector[i]->Draw(m_nodeList[i]->
GetPosition() + wxPoint2DDouble(-h / 2, w + 6.0), gc, pi / 2.0, guiColour->enabled);
103 else if (m_angle == 180.0) {
104 double w =
static_cast<double>(m_symbolSize.GetWidth());
105 double h =
static_cast<double>(m_symbolSize.GetHeight());
106 m_symbol.
Draw(m_nodeList[m_nodeList.size() - 1]->GetPosition() + wxPoint2DDouble(6.0, -h / 2.0), gc, 0, guiColour->bus);
107 for (
unsigned int i = 0; i < m_gcTextInputVector.size(); ++i) {
108 w =
static_cast<double>(m_gcTextInputVector[i]->GetWidth());
109 h =
static_cast<double>(m_gcTextInputVector[i]->GetHeight());
110 m_gcTextInputVector[i]->Draw(m_nodeList[i]->
GetPosition() - wxPoint2DDouble(w + 6.0, h / 2.0), gc, 0, guiColour->enabled);
113 else if (m_angle == 270.0) {
114 double w =
static_cast<double>(m_symbolSize.GetWidth());
115 double h =
static_cast<double>(m_symbolSize.GetHeight());
116 m_symbol.
Draw(m_nodeList[m_nodeList.size() - 1]->GetPosition() + wxPoint2DDouble(-w / 2, 6.0), gc, 0, guiColour->bus);
117 for (
unsigned int i = 0; i < m_gcTextInputVector.size(); ++i) {
118 w =
static_cast<double>(m_gcTextInputVector[i]->GetWidth());
119 h =
static_cast<double>(m_gcTextInputVector[i]->GetHeight());
120 m_gcTextInputVector[i]->Draw(m_nodeList[i]->
GetPosition() - wxPoint2DDouble(-h / 2, w + 6.0), gc, -pi / 2.0, guiColour->enabled);
124 gc->SetPen(*wxTRANSPARENT_PEN);
125 gc->SetBrush(guiColour->enabled);
132 mathExprForm.CenterOnParent();
133 if (mathExprForm.ShowModal() == wxID_OK) {
145 if (m_angle >= 360.0)
147 else if (m_angle < 0)
152 for (
auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
154 node->Rotate(clockwise);
158void MathExpression::SetFont(wxFont& font)
161 for (
auto& txtInput : m_gcTextInputVector) {
162 if (txtInput) txtInput->SetFont(font);
167bool MathExpression::Solve(
double* input,
double timeStep)
174 m_inputValues[0] = input[1];
175 m_inputValues[1] = timeStep;
176 m_inputValues[2] = input[2];
178 for (
auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) {
180 if (node->GetNodeType() != Node::NodeType::NODE_OUT) {
181 if (!node->IsConnected()) {
182 m_inputValues[i] = 0.0;
185 for (
auto itC = m_childList.begin(), itCEnd = m_childList.end(); itC != itCEnd; ++itC) {
187 auto nodeList = cLine->GetNodeList();
188 for (
auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
189 Node* childNode = *itCN;
190 if (childNode == node) {
191 m_inputValues[i] = cLine->GetValue();
202 double result = m_fparser.Eval(m_inputValues);
203 if (m_fparser.EvalError() != 0)
return false;
211 copy->m_gcTextInputVector.clear();
212 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
213 copy->m_gcTextInputVector.push_back((*it)->GetCopy());
218void MathExpression::UpdatePoints()
220 CalculateBlockSize(
static_cast<double>(m_nodeList.size()) - 1.0);
222 if (m_nodeList.size() == 2)
225 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
226 else if (m_angle == 90.0)
227 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
228 else if (m_angle == 180.0)
229 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
230 else if (m_angle == 270.0)
231 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
234 for (
unsigned int i = 0; i < m_nodeList.size() - 1; ++i) {
236 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 9 + 18 * i - m_height / 2));
237 else if (m_angle == 90.0)
238 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 9 - 18 * i, -m_height / 2));
239 else if (m_angle == 180.0)
240 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, m_height / 2 - 9 - 18 * i));
241 else if (m_angle == 270.0)
242 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(9 + 18 * i - m_width / 2, m_height / 2));
246 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
247 else if (m_angle == 90.0)
248 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
249 else if (m_angle == 180.0)
250 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
251 else if (m_angle == 270.0)
252 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
257void MathExpression::AddInNode()
259 Node* newNode =
new Node(wxPoint2DDouble(0, 0), Node::NodeType::NODE_IN, m_borderSize);
260 newNode->SetAngle(m_angle);
261 m_nodeList.insert(m_nodeList.end() - 1, newNode);
264void MathExpression::RemoveInNode()
266 Node* nodeToRemove = *(m_nodeList.end() - 2);
267 bool foundChild =
false;
268 for (
auto it = m_childList.begin(), itEnd = m_childList.end(); it != itEnd; ++it) {
270 auto childNodeList = child->GetNodeList();
271 for (
auto itN = childNodeList.begin(), itEndN = childNodeList.end(); itN != itEndN; ++itN) {
273 if (node == nodeToRemove) {
280 if (foundChild)
break;
282 m_nodeList.erase(m_nodeList.end() - 2);
285void MathExpression::CalculateBlockSize(
double numInNodes)
288 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
289 if (m_maxSringSize < (*it)->GetWidth()) m_maxSringSize = (*it)->GetWidth();
291 if (m_angle == 0.0 || m_angle == 180.0) {
292 m_height = 18.0 * numInNodes;
293 if (m_height < m_minimumSize) m_height = m_minimumSize;
294 m_width = m_maxSringSize + m_symbolSize.GetWidth() + 18;
297 m_width = 18.0 * numInNodes;
298 if (m_width < m_minimumSize) m_width = m_minimumSize;
299 m_height = m_maxSringSize + m_symbolSize.GetHeight() + 18;
305 bool isTextureOK =
true;
306 m_symbol.
SetText(m_symbol.GetText());
307 for (
auto& txtInput : m_gcTextInputVector)
309 txtInput->SetText(txtInput->GetText());
314void MathExpression::SetVariables(std::vector<wxString> variablesVector)
316 m_variablesVector = variablesVector;
317 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
delete* it; }
318 m_gcTextInputVector.clear();
320 for (
auto& it : m_variablesVector) {
322 newInputText->SetFont(m_font);
323 m_gcTextInputVector.push_back(newInputText);
329bool MathExpression::Initialize()
331 m_variables =
"time,step,switch,";
332 for (
auto it = m_variablesVector.begin(), itEnd = m_variablesVector.end(); it != itEnd; ++it)
333 m_variables += *(it)+
",";
334 m_variables.RemoveLast();
337 int currentLang = wxLocale::GetSystemLanguage();
338 wxLocale newLocale(wxLANGUAGE_ENGLISH_US);
339 int parserRes = m_fparser.Parse(
static_cast<std::string
>(m_mathExpression),
static_cast<std::string
>(m_variables));
340 if (parserRes != -1)
return false;
341 wxLocale oldLocale(currentLang);
343 if (m_inputValues)
delete m_inputValues;
344 m_inputValues =
new double[m_variablesVector.size() + 3];
347 m_fparser.Optimize();
354rapidxml::xml_node<>* MathExpression::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
356 auto elementNode = XMLParser::AppendNode(doc, elementListNode,
"MathExpr");
357 XMLParser::SetNodeAttribute(doc, elementNode,
"ID", m_elementID);
359 SaveCADProperties(doc, elementNode);
360 SaveControlNodes(doc, elementNode);
363 auto variablesNode = XMLParser::AppendNode(doc, elementNode,
"VariableList");
364 for (
unsigned int i = 0; i < m_variablesVector.size(); ++i) {
365 auto variable = XMLParser::AppendNode(doc, variablesNode,
"Variable");
366 XMLParser::SetNodeValue(doc, variable, m_variablesVector[i]);
368 auto mathExprValue = XMLParser::AppendNode(doc, elementNode,
"MathExprValue");
369 XMLParser::SetNodeValue(doc, mathExprValue, m_mathExpression);
374bool MathExpression::OpenElement(rapidxml::xml_node<>* elementNode)
376 if (!OpenCADProperties(elementNode))
return false;
377 if (!OpenControlNodes(elementNode))
return false;
380 std::vector<wxString> variables;
381 auto variablesNode = elementNode->first_node(
"VariableList");
382 auto variable = variablesNode->first_node(
"Variable");
384 variables.push_back(variable->value());
385 variable = variable->next_sibling(
"Variable");
387 SetVariables(variables);
389 auto mathExprValueNode = elementNode->first_node(
"MathExprValue");
390 m_mathExpression = mathExprValueNode->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...
wxPoint2DDouble GetPosition() const
Get the element position.
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.
Class to draw text on Graphics Context using wxWidgets.
virtual void Draw(wxPoint2DDouble position, wxGraphicsContext *gc, double angle=0.0, wxColour colour= *wxBLACK) const
Draw the text in wxGraphicsContext.
virtual void SetText(wxString text)
Set correctly a new text string.
A generic math expression block that can perform math and conditional operations with the inputs.
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+.
virtual bool UpdateText()
Update the OpenGL text in the element (if present).
virtual bool ShowForm(wxWindow *parent, Element *element, wxWindow *workspace=nullptr)
Show element data form.
virtual void Rotate(bool clockwise=true)
Rotate the element.
Node of a control element. This class manages the user interaction with the connection and control el...