// File: func.cpp // Author: Brian Allen Vanderburg II // Purpose: ExprEval internal functions //------------------------------------------------------------------------------ // Includes #include #include #include #include #include #include "autodiff/reverse/var/var.hpp" #include "defs.h" #include "funclist.h" #include "node.h" #include "except.h" using namespace ExprEval; // Anonymous namespace for items namespace { // Absolute value //-------------------------------------------------------------------------- template class abs_FunctionNode : public FunctionNode { public: explicit abs_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { if constexpr (std::is_same_v) return fabs(this->m_nodes[0]->Evaluate()); else return abs(this->m_nodes[0]->Evaluate()); } }; template class abs_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "abs"; } FunctionNode *DoCreate(Expression *expr) override { return new abs_FunctionNode(expr); } }; // Modulus //-------------------------------------------------------------------------- template class mod_FunctionNode : public FunctionNode { public: explicit mod_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = fmod(this->m_nodes[0]->Evaluate(), this->m_nodes[1]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class mod_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "mod"; } FunctionNode *DoCreate(Expression *expr) override { return new mod_FunctionNode(expr); } }; // Integer part //-------------------------------------------------------------------------- template class ipart_FunctionNode : public FunctionNode { public: explicit ipart_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { Value result; modf(this->m_nodes[0]->Evaluate(), &result); return result; } }; template class ipart_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "ipart"; } FunctionNode *DoCreate(Expression *expr) override { return new ipart_FunctionNode(expr); } }; // Fraction part //-------------------------------------------------------------------------- template class fpart_FunctionNode : public FunctionNode { public: explicit fpart_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { Value dummy; return modf(this->m_nodes[0]->Evaluate(), &dummy); } }; template class fpart_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "fpart"; } FunctionNode *DoCreate(Expression *expr) override { return new fpart_FunctionNode(expr); } }; // Minimum //-------------------------------------------------------------------------- template class min_FunctionNode : public FunctionNode { public: explicit min_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, -1, 0, 0); } Value DoEvaluate() override { Value result = 0; size_t pos = 0; for (const auto& node : this->m_nodes) { Value tmp = node->Evaluate(); if (pos == 0 || tmp < result) result = tmp; ++pos; } return result; } }; template class min_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "min"; } FunctionNode *DoCreate(Expression *expr) override { return new min_FunctionNode(expr); } }; // Maximum //-------------------------------------------------------------------------- template class max_FunctionNode : public FunctionNode { public: explicit max_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, -1, 0, 0); } Value DoEvaluate() override { Value result = 0; size_t pos = 0; for (const auto& node : this->m_nodes) { Value tmp = node->Evaluate(); if (pos == 0 || tmp > result) result = tmp; ++pos; } return result; } }; template class max_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "max"; } FunctionNode *DoCreate(Expression *expr) override { return new max_FunctionNode(expr); } }; // Square root //-------------------------------------------------------------------------- template class sqrt_FunctionNode : public FunctionNode { public: explicit sqrt_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = sqrt(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class sqrt_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "sqrt"; } FunctionNode *DoCreate(Expression *expr) override { return new sqrt_FunctionNode(expr); } }; // Sine //-------------------------------------------------------------------------- template class sin_FunctionNode : public FunctionNode { public: explicit sin_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = sin(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class sin_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "sin"; } FunctionNode *DoCreate(Expression *expr) override { return new sin_FunctionNode(expr); } }; // Cosine //-------------------------------------------------------------------------- template class cos_FunctionNode : public FunctionNode { public: explicit cos_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = cos(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class cos_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "cos"; } FunctionNode *DoCreate(Expression *expr) override { return new cos_FunctionNode(expr); } }; // Tangent //-------------------------------------------------------------------------- template class tan_FunctionNode : public FunctionNode { public: explicit tan_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = tan(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class tan_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "tan"; } FunctionNode *DoCreate(Expression *expr) override { return new tan_FunctionNode(expr); } }; // Hyperbolic Sine //-------------------------------------------------------------------------- template class sinh_FunctionNode : public FunctionNode { public: explicit sinh_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; auto result = sinh(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class sinh_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "sinh"; } FunctionNode *DoCreate(Expression *expr) override { return new sinh_FunctionNode(expr); } }; // Hyperbolic Cosine //-------------------------------------------------------------------------- template class cosh_FunctionNode : public FunctionNode { public: explicit cosh_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = cosh(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class cosh_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "cosh"; } FunctionNode *DoCreate(Expression *expr) override { return new cosh_FunctionNode(expr); } }; // Hyperbolic Tangent //-------------------------------------------------------------------------- template class tanh_FunctionNode : public FunctionNode { public: explicit tanh_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = tanh(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class tanh_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "tanh"; } FunctionNode *DoCreate(Expression *expr) override { return new tanh_FunctionNode(expr); } }; // Arc Sine //-------------------------------------------------------------------------- template class asin_FunctionNode : public FunctionNode { public: explicit asin_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = asin(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class asin_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "asin"; } FunctionNode *DoCreate(Expression *expr) override { return new asin_FunctionNode(expr); } }; // Arc Cosine //-------------------------------------------------------------------------- template class acos_FunctionNode : public FunctionNode { public: explicit acos_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = acos(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class acos_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "acos"; } FunctionNode *DoCreate(Expression *expr) override { return new acos_FunctionNode(expr); } }; // Arc Tangent //-------------------------------------------------------------------------- template class atan_FunctionNode : public FunctionNode { public: explicit atan_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = atan(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class atan_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "atan"; } FunctionNode *DoCreate(Expression *expr) override { return new atan_FunctionNode(expr); } }; // Arc Tangent 2: atan2(y, x) //-------------------------------------------------------------------------- template class atan2_FunctionNode : public FunctionNode { public: explicit atan2_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = atan2(this->m_nodes[0]->Evaluate(), this->m_nodes[1]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class atan2_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "atan2"; } FunctionNode *DoCreate(Expression *expr) override { return new atan2_FunctionNode(expr); } }; // Log //-------------------------------------------------------------------------- template class log_FunctionNode : public FunctionNode { public: explicit log_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = log10(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class log_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "log"; } FunctionNode *DoCreate(Expression *expr) override { return new log_FunctionNode(expr); } }; // Ln //-------------------------------------------------------------------------- template class ln_FunctionNode : public FunctionNode { public: explicit ln_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = log(this->m_nodes[0]->Evaluate()); if(errno) throw(MathException(this->GetName())); return result; } }; template class ln_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "ln"; } FunctionNode *DoCreate(Expression *expr) override { return new ln_FunctionNode(expr); } }; // Exp //-------------------------------------------------------------------------- template class exp_FunctionNode : public FunctionNode { public: explicit exp_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { errno = 0; Value x = this->m_nodes[0]->Evaluate(); Value result = exp(x); if (errno && x > Value(0.0)) // Fixed: No exception on underflow throw(MathException(this->GetName())); return result; } }; template class exp_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "exp"; } FunctionNode *DoCreate(Expression *expr) override { return new exp_FunctionNode(expr); } }; // Logn //-------------------------------------------------------------------------- template class logn_FunctionNode : public FunctionNode { public: explicit logn_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 0, 0); } Value DoEvaluate() override { errno = 0; // Check for division by zero Value tmp = log(this->m_nodes[1]->Evaluate()); if(tmp == 0.0) throw(MathException(this->GetName())); // Calculate result Value result = log(this->m_nodes[0]->Evaluate()) / tmp; if(errno) throw(MathException(this->GetName())); return result; } }; template class logn_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "logn"; } FunctionNode *DoCreate(Expression *expr) override { return new logn_FunctionNode(expr); } }; template class pow_FunctionNode : public FunctionNode { public: explicit pow_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 0, 0); } Value DoEvaluate() override { errno = 0; Value result = pow(this->m_nodes[0]->Evaluate(), this->m_nodes[1]->Evaluate()); if constexpr (std::is_same_v) { // disable exception with autodiff if(errno) throw(MathException(this->GetName())); } return result; } }; template class pow_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "pow"; } FunctionNode *DoCreate(Expression *expr) override { return new pow_FunctionNode(expr); } }; // Ceil //-------------------------------------------------------------------------- template class ceil_FunctionNode : public FunctionNode { public: explicit ceil_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { return ceil(this->m_nodes[0]->Evaluate()); } }; template class ceil_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "ceil"; } FunctionNode *DoCreate(Expression *expr) override { return new ceil_FunctionNode(expr); } }; // Floor //-------------------------------------------------------------------------- template class floor_FunctionNode : public FunctionNode { public: explicit floor_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { return floor(this->m_nodes[0]->Evaluate()); } }; template class floor_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "floor"; } FunctionNode *DoCreate(Expression *expr) override { return new floor_FunctionNode(expr); } }; // Rand //-------------------------------------------------------------------------- // Get next random (0,1) inline double NextRandom(double *seed) { long a = (long)(*seed) * 214013L + 2531011L; *seed = (double)a; return (double)((a >> 16) & 0x7FFF) / 32767.0; } template class rand_FunctionNode : public FunctionNode { public: explicit rand_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(0, 0, 1, 1); } Value DoEvaluate() override { return NextRandom(this->m_refs[0]); } }; template class rand_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "rand"; } FunctionNode *DoCreate(Expression *expr) override { return new rand_FunctionNode(expr); } }; // Random //-------------------------------------------------------------------------- template class random_FunctionNode : public FunctionNode { public: explicit random_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 1, 1); } Value DoEvaluate() override { Value a = this->m_nodes[0]->Evaluate(); Value b = this->m_nodes[1]->Evaluate(); return NextRandom(this->m_refs[0]) * (b - a) + a; } }; template class random_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "random"; } FunctionNode *DoCreate(Expression *expr) override { return new random_FunctionNode(expr); } }; // Randomize //-------------------------------------------------------------------------- template class randomize_FunctionNode : public FunctionNode { public: explicit randomize_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(0, 0, 1, 1); } Value DoEvaluate() override { static long curcall = 1; *this->m_refs[0] = (Value)(((clock() + 1024u + curcall) * time(NULL)) % 2176971487u); curcall++; return 0.0; } }; template class randomize_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "randomize"; } FunctionNode *DoCreate(Expression *expr) override { return new randomize_FunctionNode(expr); } }; // Radians to degrees //-------------------------------------------------------------------------- template class deg_FunctionNode : public FunctionNode { public: explicit deg_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { return (this->m_nodes[0]->Evaluate() * 180.0) / M_PI; } }; template class deg_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "deg"; } FunctionNode *DoCreate(Expression *expr) override { return new deg_FunctionNode(expr); } }; // Degrees to radians //-------------------------------------------------------------------------- template class rad_FunctionNode : public FunctionNode { public: explicit rad_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { return (this->m_nodes[0]->Evaluate() * M_PI) / 180.0; } }; template class rad_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "rad"; } FunctionNode *DoCreate(Expression *expr) override { return new rad_FunctionNode(expr); } }; // Rectangular to polar: rect2pol(x, y, &distance, &angle) //-------------------------------------------------------------------------- template class rect2pol_FunctionNode : public FunctionNode { public: explicit rect2pol_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 2, 2); } Value DoEvaluate() override { errno = 0; Value x = this->m_nodes[0]->Evaluate(); Value y = this->m_nodes[1]->Evaluate(); Value d = hypot(x, y); Value a = atan2(y, x); if(errno) throw(MathException(this->GetName())); *this->m_refs[0] = d; if(a < 0.0) *this->m_refs[1] = a + (2.0 * M_PI); else *this->m_refs[1] = a; return d; } }; template class rect2pol_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "rect2pol"; } FunctionNode *DoCreate(Expression *expr) override { return new rect2pol_FunctionNode(expr); } }; // Polar to rectangular: pol2rect(distance, angle, &x, &y) //-------------------------------------------------------------------------- template class pol2rect_FunctionNode : public FunctionNode { public: explicit pol2rect_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 2, 2); } Value DoEvaluate() override { errno = 0; Value d = this->m_nodes[0]->Evaluate(); Value a = this->m_nodes[1]->Evaluate(); Value x = d * cos(a); Value y = d * sin(a); if(errno) throw(MathException(this->GetName())); *this->m_refs[0] = x; *this->m_refs[1] = y; return x; } }; template class pol2rect_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "pol2rect"; } FunctionNode *DoCreate(Expression *expr) override { return new pol2rect_FunctionNode(expr); } }; // If //-------------------------------------------------------------------------- template class if_FunctionNode : public FunctionNode { public: explicit if_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(3, 3, 0, 0); } Value DoEvaluate() override { Value c = this->m_nodes[0]->Evaluate(); if(c == 0.0) return this->m_nodes[2]->Evaluate(); else return this->m_nodes[1]->Evaluate(); } }; template class if_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "if"; } FunctionNode *DoCreate(Expression *expr) override { return new if_FunctionNode(expr); } }; // Select //-------------------------------------------------------------------------- template class select_FunctionNode : public FunctionNode { public: explicit select_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(3, 4, 0, 0); } Value DoEvaluate() override { Value c = this->m_nodes[0]->Evaluate(); if(c < 0.0) return this->m_nodes[1]->Evaluate(); else if(c == 0.0) return this->m_nodes[2]->Evaluate(); else { if(this->m_nodes.size() == 3) return this->m_nodes[2]->Evaluate(); else return this->m_nodes[3]->Evaluate(); } } }; template class select_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "select"; } FunctionNode *DoCreate(Expression *expr) override { return new select_FunctionNode(expr); } }; // Equal //-------------------------------------------------------------------------- template class equal_FunctionNode : public FunctionNode { public: explicit equal_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 0, 0); } Value DoEvaluate() override { if(this->m_nodes[0]->Evaluate() == this->m_nodes[1]->Evaluate()) return 1.0; else return 0.0; } }; template class equal_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "equal"; } FunctionNode *DoCreate(Expression *expr) override { return new equal_FunctionNode(expr); } }; // Above //-------------------------------------------------------------------------- template class above_FunctionNode : public FunctionNode { public: explicit above_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 0, 0); } Value DoEvaluate() override { if(this->m_nodes[0]->Evaluate() > this->m_nodes[1]->Evaluate()) return 1.0; else return 0.0; } }; template class above_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "above"; } FunctionNode *DoCreate(Expression *expr) override { return new above_FunctionNode(expr); } }; // Below //-------------------------------------------------------------------------- template class below_FunctionNode : public FunctionNode { public: explicit below_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 0, 0); } Value DoEvaluate() override { if(this->m_nodes[0]->Evaluate() < this->m_nodes[1]->Evaluate()) return 1.0; else return 0.0; } }; template class below_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "below"; } FunctionNode *DoCreate(Expression *expr) override { return new below_FunctionNode(expr); } }; // Clip //-------------------------------------------------------------------------- template class clip_FunctionNode : public FunctionNode { public: explicit clip_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(3, 3, 0, 0); } Value DoEvaluate() override { Value v = this->m_nodes[0]->Evaluate(); Value a = this->m_nodes[1]->Evaluate(); Value b = this->m_nodes[2]->Evaluate(); if(v < a) return a; else if(v > b) return b; else return v; } }; template class clip_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "clip"; } FunctionNode *DoCreate(Expression *expr) override { return new clip_FunctionNode(expr); } }; // Clamp //-------------------------------------------------------------------------- template class clamp_FunctionNode : public FunctionNode { public: explicit clamp_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(3, 3, 0, 0); } Value DoEvaluate() override { Value v = this->m_nodes[0]->Evaluate(); Value a = this->m_nodes[1]->Evaluate(); Value b = this->m_nodes[2]->Evaluate(); if(a == b) return a; else { Value tmp = fmod(v - a, b - a); if(tmp < 0) return tmp + b; else return tmp + a; } } }; template class clamp_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "clamp"; } FunctionNode *DoCreate(Expression *expr) override { return new clamp_FunctionNode(expr); } }; // Rescale //-------------------------------------------------------------------------- template class rescale_FunctionNode : public FunctionNode { public: explicit rescale_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(5, 5, 0, 0); } Value DoEvaluate() override { Value pnt = this->m_nodes[0]->Evaluate(); Value o1 = this->m_nodes[1]->Evaluate(); Value o2 = this->m_nodes[2]->Evaluate(); Value n1 = this->m_nodes[3]->Evaluate(); Value n2 = this->m_nodes[4]->Evaluate(); Value odiff = o2 - o1; if(odiff == 0.0) return n1; else { return (pnt - o1) * (n2 - n1) / odiff + n1; } } }; template class rescale_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "rescale"; } FunctionNode *DoCreate(Expression *expr) override { return new rescale_FunctionNode(expr); } }; // Poly: poly(x, c3, c2, c1, c0): c3*x^3 + c2*x^2 + c1*x + c0 //-------------------------------------------------------------------------- template class poly_FunctionNode : public FunctionNode { public: explicit poly_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, -1, 0, 0); } Value DoEvaluate() override { Value total = 0.0; double curpow; curpow = (double)(this->m_nodes.size() - 2); // Value of x Value x = this->m_nodes[0]->Evaluate(); errno = 0; for (const auto& node : this->m_nodes) { total += node->Evaluate() * pow(x, curpow); curpow -= 1.0; } if(errno) throw(MathException(this->GetName())); return total; } }; template class poly_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "poly"; } FunctionNode *DoCreate(Expression *expr) override { return new poly_FunctionNode(expr); } }; // And //-------------------------------------------------------------------------- template class and_FunctionNode : public FunctionNode { public: explicit and_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 0, 0); } Value DoEvaluate() override { if(this->m_nodes[0]->Evaluate() == 0.0 || this->m_nodes[1]->Evaluate() == 0.0) return 0.0; else return 1.0; } }; template class and_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "and"; } FunctionNode *DoCreate(Expression *expr) override { return new and_FunctionNode(expr); } }; // Or //-------------------------------------------------------------------------- template class or_FunctionNode : public FunctionNode { public: explicit or_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(2, 2, 0, 0); } Value DoEvaluate() override { if(this->m_nodes[0]->Evaluate() == 0.0 && this->m_nodes[1]->Evaluate() == 0.0) return 0.0; else return 1.0; } }; template class or_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "or"; } FunctionNode *DoCreate(Expression *expr) override { return new or_FunctionNode(expr); } }; // Not //-------------------------------------------------------------------------- template class not_FunctionNode : public FunctionNode { public: explicit not_FunctionNode(Expression *expr) : FunctionNode(expr) { this->SetArgumentCount(1, 1, 0, 0); } Value DoEvaluate() override { if(this->m_nodes[0]->Evaluate() == 0.0) return 1.0; else return 0.0; } }; template class not_FunctionFactory : public FunctionFactory { public: std::string GetName() const override { return "not"; } FunctionNode *DoCreate(Expression *expr) override { return new not_FunctionNode(expr); } }; } // namespace // Initialize default functions template void FunctionList::AddDefaultFunctions() { #define ADDFUNCTION(name) \ aptr(FunctionFactory) name ## _func(new name ## _FunctionFactory()); \ m_functions.push_back(name ## _func.get()); \ name ## _func.release(); ADDFUNCTION(abs); ADDFUNCTION(sqrt); ADDFUNCTION(sin); ADDFUNCTION(cos); ADDFUNCTION(tan); ADDFUNCTION(sinh); ADDFUNCTION(cosh); ADDFUNCTION(tanh); ADDFUNCTION(asin); ADDFUNCTION(acos); ADDFUNCTION(atan); ADDFUNCTION(atan2); ADDFUNCTION(log); ADDFUNCTION(ln); ADDFUNCTION(exp); ADDFUNCTION(logn); ADDFUNCTION(pow); ADDFUNCTION(deg); ADDFUNCTION(rad); ADDFUNCTION(rect2pol); ADDFUNCTION(pol2rect); ADDFUNCTION(if); // Preprocess will take care of this beforehand ADDFUNCTION(select); ADDFUNCTION(equal); ADDFUNCTION(above); ADDFUNCTION(below); ADDFUNCTION(clip); ADDFUNCTION(rescale); ADDFUNCTION(poly); ADDFUNCTION(and); ADDFUNCTION(or); ADDFUNCTION(not); if constexpr (std::is_same_v) { ADDFUNCTION(mod); ADDFUNCTION(ipart); ADDFUNCTION(fpart); ADDFUNCTION(min); ADDFUNCTION(max); ADDFUNCTION(ceil); ADDFUNCTION(floor); ADDFUNCTION(rand); ADDFUNCTION(random); ADDFUNCTION(randomize); ADDFUNCTION(clamp); } } namespace ExprEval { template void FunctionList::AddDefaultFunctions(); template class FunctionList; }