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]));
38 m_symbol.SetFont(wxFont(12, wxFONTFAMILY_ROMAN, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_BOLD));
39 m_symbol.SetText(
"f(x)");
40 m_symbolSize = wxSize(m_symbol.GetWidth(), m_symbol.GetHeight());
42 CalculateBlockSize(
static_cast<double>(m_variablesVector.size()));
44 for (
unsigned int i = 0; i < m_variablesVector.size(); ++i) {
45 wxPoint2DDouble nodePosition(0, 0);
46 if (m_variablesVector.size() == 1) {
47 nodePosition = m_position + wxPoint2DDouble(-m_width / 2, 0);
50 nodePosition = m_position + wxPoint2DDouble(-m_width / 2, 9 + 18 * i - m_height / 2);
52 Node* nodeIn =
new Node(nodePosition, Node::NodeType::NODE_IN, m_borderSize);
53 nodeIn->StartMove(m_position);
54 m_nodeList.push_back(nodeIn);
56 Node* nodeOut =
new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NodeType::NODE_OUT, m_borderSize);
57 nodeOut->SetAngle(180.0);
58 nodeOut->StartMove(m_position);
59 m_nodeList.push_back(nodeOut);
64MathExpression::~MathExpression()
66 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
delete* it; }
67 m_gcTextInputVector.clear();
68 for (
auto& node : m_nodeList) if (node) delete node;
135 double pi = 3.1415926535897932;
137 gc->SetPen(*wxTRANSPARENT_PEN);
138 gc->SetBrush(wxBrush(m_selectionColour));
139 double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
140 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);
142 gc->SetPen(wxPen(wxColour(0, 0, 0, 255), 1));
143 gc->SetBrush(wxBrush(wxColour(255, 255, 255, 255)));
144 gc->DrawRectangle(m_position.m_x - m_width / 2, m_position.m_y - m_height / 2, m_width, m_height);
147 if (m_angle == 0.0) {
148 double w =
static_cast<double>(m_symbolSize.GetWidth());
149 double h =
static_cast<double>(m_symbolSize.GetHeight());
150 m_symbol.
Draw(m_nodeList[m_nodeList.size() - 1]->GetPosition() - wxPoint2DDouble(w + 6.0, h / 2.0), gc, 0, wxColour(0, 77, 255, 255));
151 for (
unsigned int i = 0; i < m_gcTextInputVector.size(); ++i) {
152 w =
static_cast<double>(m_gcTextInputVector[i]->GetWidth());
153 h =
static_cast<double>(m_gcTextInputVector[i]->GetHeight());
154 m_gcTextInputVector[i]->Draw(m_nodeList[i]->
GetPosition() + wxPoint2DDouble(6.0, -h / 2.0), gc);
157 else if (m_angle == 90.0) {
158 double w =
static_cast<double>(m_symbolSize.GetWidth());
159 double h =
static_cast<double>(m_symbolSize.GetHeight());
160 m_symbol.
Draw(m_nodeList[m_nodeList.size() - 1]->GetPosition() - wxPoint2DDouble(w / 2, h + 6.0), gc, 0, wxColour(0, 77, 255, 255));
161 for (
unsigned int i = 0; i < m_gcTextInputVector.size(); ++i) {
162 w =
static_cast<double>(m_gcTextInputVector[i]->GetWidth());
163 h =
static_cast<double>(m_gcTextInputVector[i]->GetHeight());
164 m_gcTextInputVector[i]->Draw(m_nodeList[i]->
GetPosition() + wxPoint2DDouble(-h / 2, w + 6.0), gc, pi / 2.0);
167 else if (m_angle == 180.0) {
168 double w =
static_cast<double>(m_symbolSize.GetWidth());
169 double h =
static_cast<double>(m_symbolSize.GetHeight());
170 m_symbol.
Draw(m_nodeList[m_nodeList.size() - 1]->GetPosition() + wxPoint2DDouble(6.0, -h / 2.0), gc, 0, wxColour(0, 77, 255, 255));
171 for (
unsigned int i = 0; i < m_gcTextInputVector.size(); ++i) {
172 w =
static_cast<double>(m_gcTextInputVector[i]->GetWidth());
173 h =
static_cast<double>(m_gcTextInputVector[i]->GetHeight());
174 m_gcTextInputVector[i]->Draw(m_nodeList[i]->
GetPosition() - wxPoint2DDouble(w + 6.0, h / 2.0), gc);
177 else if (m_angle == 270.0) {
178 double w =
static_cast<double>(m_symbolSize.GetWidth());
179 double h =
static_cast<double>(m_symbolSize.GetHeight());
180 m_symbol.
Draw(m_nodeList[m_nodeList.size() - 1]->GetPosition() + wxPoint2DDouble(-w / 2, 6.0), gc, 0, wxColour(0, 77, 255, 255));
181 for (
unsigned int i = 0; i < m_gcTextInputVector.size(); ++i) {
182 w =
static_cast<double>(m_gcTextInputVector[i]->GetWidth());
183 h =
static_cast<double>(m_gcTextInputVector[i]->GetHeight());
184 m_gcTextInputVector[i]->Draw(m_nodeList[i]->
GetPosition() - wxPoint2DDouble(-h / 2, w + 6.0), gc, -pi / 2.0);
188 gc->SetPen(*wxTRANSPARENT_PEN);
189 gc->SetBrush(*wxBLACK_BRUSH);
196 mathExprForm.CenterOnParent();
197 if (mathExprForm.ShowModal() == wxID_OK) {
209 if (m_angle >= 360.0)
211 else if (m_angle < 0)
216 for (
auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
218 node->Rotate(clockwise);
222bool MathExpression::Solve(
double* input,
double timeStep)
229 m_inputValues[0] = input[1];
230 m_inputValues[1] = timeStep;
231 m_inputValues[2] = input[2];
233 for (
auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) {
235 if (node->GetNodeType() != Node::NodeType::NODE_OUT) {
236 if (!node->IsConnected()) {
237 m_inputValues[i] = 0.0;
240 for (
auto itC = m_childList.begin(), itCEnd = m_childList.end(); itC != itCEnd; ++itC) {
242 auto nodeList = cLine->GetNodeList();
243 for (
auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
244 Node* childNode = *itCN;
245 if (childNode == node) {
246 m_inputValues[i] = cLine->GetValue();
257 double result = m_fparser.Eval(m_inputValues);
258 if (m_fparser.EvalError() != 0)
return false;
266 copy->m_gcTextInputVector.clear();
267 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
268 copy->m_gcTextInputVector.push_back((*it)->GetCopy());
273void MathExpression::UpdatePoints()
275 CalculateBlockSize(
static_cast<double>(m_nodeList.size()) - 1.0);
277 if (m_nodeList.size() == 2)
280 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
281 else if (m_angle == 90.0)
282 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
283 else if (m_angle == 180.0)
284 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
285 else if (m_angle == 270.0)
286 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
289 for (
unsigned int i = 0; i < m_nodeList.size() - 1; ++i) {
291 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 9 + 18 * i - m_height / 2));
292 else if (m_angle == 90.0)
293 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 9 - 18 * i, -m_height / 2));
294 else if (m_angle == 180.0)
295 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, m_height / 2 - 9 - 18 * i));
296 else if (m_angle == 270.0)
297 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(9 + 18 * i - m_width / 2, m_height / 2));
301 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
302 else if (m_angle == 90.0)
303 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
304 else if (m_angle == 180.0)
305 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
306 else if (m_angle == 270.0)
307 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
312void MathExpression::AddInNode()
314 Node* newNode =
new Node(wxPoint2DDouble(0, 0), Node::NodeType::NODE_IN, m_borderSize);
315 newNode->SetAngle(m_angle);
316 m_nodeList.insert(m_nodeList.end() - 1, newNode);
319void MathExpression::RemoveInNode()
321 Node* nodeToRemove = *(m_nodeList.end() - 2);
322 bool foundChild =
false;
323 for (
auto it = m_childList.begin(), itEnd = m_childList.end(); it != itEnd; ++it) {
325 auto childNodeList = child->GetNodeList();
326 for (
auto itN = childNodeList.begin(), itEndN = childNodeList.end(); itN != itEndN; ++itN) {
328 if (node == nodeToRemove) {
335 if (foundChild)
break;
337 m_nodeList.erase(m_nodeList.end() - 2);
340void MathExpression::CalculateBlockSize(
double numInNodes)
343 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
344 if (m_maxSringSize < (*it)->GetWidth()) m_maxSringSize = (*it)->GetWidth();
346 if (m_angle == 0.0 || m_angle == 180.0) {
347 m_height = 18.0 * numInNodes;
348 if (m_height < m_minimumSize) m_height = m_minimumSize;
349 m_width = m_maxSringSize + m_symbolSize.GetWidth() + 18;
352 m_width = 18.0 * numInNodes;
353 if (m_width < m_minimumSize) m_width = m_minimumSize;
354 m_height = m_maxSringSize + m_symbolSize.GetHeight() + 18;
360 bool isTextureOK =
true;
361 m_symbol.
SetText(m_symbol.GetText());
363 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
364 (*it)->SetText((*it)->GetText());
370void MathExpression::SetVariables(std::vector<wxString> variablesVector)
372 m_variablesVector = variablesVector;
374 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
delete* it; }
375 m_gcTextInputVector.clear();
377 for (
auto it = m_variablesVector.begin(), itEnd = m_variablesVector.end(); it != itEnd; ++it)
378 m_gcTextInputVector.push_back(
new GCText(*(it)));
381bool MathExpression::Initialize()
383 m_variables =
"time,step,switch,";
384 for (
auto it = m_variablesVector.begin(), itEnd = m_variablesVector.end(); it != itEnd; ++it)
385 m_variables += *(it)+
",";
386 m_variables.RemoveLast();
389 int currentLang = wxLocale::GetSystemLanguage();
390 wxLocale newLocale(wxLANGUAGE_ENGLISH_US);
391 int parserRes = m_fparser.Parse(
static_cast<std::string
>(m_mathExpression),
static_cast<std::string
>(m_variables));
392 if (parserRes != -1)
return false;
393 wxLocale oldLocale(currentLang);
395 if (m_inputValues)
delete m_inputValues;
396 m_inputValues =
new double[m_variablesVector.size() + 3];
399 m_fparser.Optimize();
406rapidxml::xml_node<>* MathExpression::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
408 auto elementNode = XMLParser::AppendNode(doc, elementListNode,
"MathExpr");
409 XMLParser::SetNodeAttribute(doc, elementNode,
"ID", m_elementID);
411 SaveCADProperties(doc, elementNode);
412 SaveControlNodes(doc, elementNode);
415 auto variablesNode = XMLParser::AppendNode(doc, elementNode,
"VariableList");
416 for (
unsigned int i = 0; i < m_variablesVector.size(); ++i) {
417 auto variable = XMLParser::AppendNode(doc, variablesNode,
"Variable");
418 XMLParser::SetNodeValue(doc, variable, m_variablesVector[i]);
420 auto mathExprValue = XMLParser::AppendNode(doc, elementNode,
"MathExprValue");
421 XMLParser::SetNodeValue(doc, mathExprValue, m_mathExpression);
426bool MathExpression::OpenElement(rapidxml::xml_node<>* elementNode)
428 if (!OpenCADProperties(elementNode))
return false;
429 if (!OpenControlNodes(elementNode))
return false;
432 std::vector<wxString> variables;
433 auto variablesNode = elementNode->first_node(
"VariableList");
434 auto variable = variablesNode->first_node(
"Variable");
436 variables.push_back(variable->value());
437 variable = variable->next_sibling(
"Variable");
439 SetVariables(variables);
441 auto mathExprValueNode = elementNode->first_node(
"MathExprValue");
442 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 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.
virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
Node of a control element. This class manages the user interaction with the connection and control el...