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;
267 copy->m_gcTextInputVector.clear();
268 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
269 copy->m_gcTextInputVector.push_back((*it)->GetCopy());
274void MathExpression::UpdatePoints()
276 CalculateBlockSize(
static_cast<double>(m_nodeList.size()) - 1.0);
278 if (m_nodeList.size() == 2)
281 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
282 else if (m_angle == 90.0)
283 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
284 else if (m_angle == 180.0)
285 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
286 else if (m_angle == 270.0)
287 m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
290 for (
unsigned int i = 0; i < m_nodeList.size() - 1; ++i) {
292 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 9 + 18 * i - m_height / 2));
293 else if (m_angle == 90.0)
294 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 9 - 18 * i, -m_height / 2));
295 else if (m_angle == 180.0)
296 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, m_height / 2 - 9 - 18 * i));
297 else if (m_angle == 270.0)
298 m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(9 + 18 * i - m_width / 2, m_height / 2));
302 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
303 else if (m_angle == 90.0)
304 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
305 else if (m_angle == 180.0)
306 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
307 else if (m_angle == 270.0)
308 m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
313void MathExpression::AddInNode()
315 Node* newNode =
new Node(wxPoint2DDouble(0, 0), Node::NodeType::NODE_IN, m_borderSize);
316 newNode->SetAngle(m_angle);
317 m_nodeList.insert(m_nodeList.end() - 1, newNode);
320void MathExpression::RemoveInNode()
322 Node* nodeToRemove = *(m_nodeList.end() - 2);
323 bool foundChild =
false;
324 for (
auto it = m_childList.begin(), itEnd = m_childList.end(); it != itEnd; ++it) {
326 auto childNodeList = child->GetNodeList();
327 for (
auto itN = childNodeList.begin(), itEndN = childNodeList.end(); itN != itEndN; ++itN) {
329 if (node == nodeToRemove) {
336 if (foundChild)
break;
338 m_nodeList.erase(m_nodeList.end() - 2);
341void MathExpression::CalculateBlockSize(
double numInNodes)
344 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
345 if (m_maxSringSize < (*it)->GetWidth()) m_maxSringSize = (*it)->GetWidth();
347 if (m_angle == 0.0 || m_angle == 180.0) {
348 m_height = 18.0 * numInNodes;
349 if (m_height < m_minimumSize) m_height = m_minimumSize;
350 m_width = m_maxSringSize + m_symbolSize.GetWidth() + 18;
353 m_width = 18.0 * numInNodes;
354 if (m_width < m_minimumSize) m_width = m_minimumSize;
355 m_height = m_maxSringSize + m_symbolSize.GetHeight() + 18;
361 bool isTextureOK =
true;
362 m_symbol.
SetText(m_symbol.GetText());
364 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
365 (*it)->SetText((*it)->GetText());
371void MathExpression::SetVariables(std::vector<wxString> variablesVector)
373 m_variablesVector = variablesVector;
375 for (
auto it = m_gcTextInputVector.begin(), itEnd = m_gcTextInputVector.end(); it != itEnd; ++it) {
delete* it; }
376 m_gcTextInputVector.clear();
378 for (
auto it = m_variablesVector.begin(), itEnd = m_variablesVector.end(); it != itEnd; ++it)
379 m_gcTextInputVector.push_back(
new GCText(*(it)));
382bool MathExpression::Initialize()
384 m_variables =
"time,step,switch,";
385 for (
auto it = m_variablesVector.begin(), itEnd = m_variablesVector.end(); it != itEnd; ++it)
386 m_variables += *(it)+
",";
387 m_variables.RemoveLast();
390 int currentLang = wxLocale::GetSystemLanguage();
391 wxLocale newLocale(wxLANGUAGE_ENGLISH_US);
392 int parserRes = m_fparser.Parse(
static_cast<std::string
>(m_mathExpression),
static_cast<std::string
>(m_variables));
393 if (parserRes != -1)
return false;
394 wxLocale oldLocale(currentLang);
396 if (m_inputValues)
delete m_inputValues;
397 m_inputValues =
new double[m_variablesVector.size() + 3];
400 m_fparser.Optimize();
407rapidxml::xml_node<>* MathExpression::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
409 auto elementNode = XMLParser::AppendNode(doc, elementListNode,
"MathExpr");
410 XMLParser::SetNodeAttribute(doc, elementNode,
"ID", m_elementID);
412 SaveCADProperties(doc, elementNode);
413 SaveControlNodes(doc, elementNode);
416 auto variablesNode = XMLParser::AppendNode(doc, elementNode,
"VariableList");
417 for (
unsigned int i = 0; i < m_variablesVector.size(); ++i) {
418 auto variable = XMLParser::AppendNode(doc, variablesNode,
"Variable");
419 XMLParser::SetNodeValue(doc, variable, m_variablesVector[i]);
421 auto mathExprValue = XMLParser::AppendNode(doc, elementNode,
"MathExprValue");
422 XMLParser::SetNodeValue(doc, mathExprValue, m_mathExpression);
427bool MathExpression::OpenElement(rapidxml::xml_node<>* elementNode)
429 if (!OpenCADProperties(elementNode))
return false;
430 if (!OpenControlNodes(elementNode))
return false;
433 std::vector<wxString> variables;
434 auto variablesNode = elementNode->first_node(
"VariableList");
435 auto variable = variablesNode->first_node(
"Variable");
437 variables.push_back(variable->value());
438 variable = variable->next_sibling(
"Variable");
440 SetVariables(variables);
442 auto mathExprValueNode = elementNode->first_node(
"MathExprValue");
443 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 bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
virtual Element * GetCopy()
Get a the element copy.
virtual bool UpdateText()
Update the OpenGL text in the element (if present).
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...