/* * OpenSCAD (www.openscad.org) * Copyright (C) 2009-2011 Clifford Wolf and * Marius Kintel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * As a special exception, you have permission to link this program * with the CGAL library and distribute executables, as long as you * follow the requirements of the GNU GPL in regard to all of the * software in the executable aside from CGAL. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "function.h" #include "expression.h" #include "context.h" #include "builtin.h" #include #include #include "mathc99.h" #include #include "stl-utils.h" AbstractFunction::~AbstractFunction() { } Value AbstractFunction::evaluate(const Context*, const std::vector&, const std::vector&) const { return Value(); } std::string AbstractFunction::dump(const std::string &indent, const std::string &name) const { std::stringstream dump; dump << indent << "abstract function " << name << "();\n"; return dump.str(); } Function::~Function() { std::for_each(this->argexpr.begin(), this->argexpr.end(), del_fun()); delete expr; } Value Function::evaluate(const Context *ctx, const std::vector &call_argnames, const std::vector &call_argvalues) const { Context c(ctx); c.args(argnames, argexpr, call_argnames, call_argvalues); if (expr) return expr->evaluate(&c); return Value(); } std::string Function::dump(const std::string &indent, const std::string &name) const { std::stringstream dump; dump << indent << "function " << name << "("; for (size_t i=0; i < argnames.size(); i++) { if (i > 0) dump << ", "; dump << argnames[i]; if (argexpr[i]) dump << " = " << *argexpr[i]; } dump << ") = " << *expr << ";\n"; return dump.str(); } BuiltinFunction::~BuiltinFunction() { } Value BuiltinFunction::evaluate(const Context *ctx, const std::vector &call_argnames, const std::vector &call_argvalues) const { return eval_func(ctx, call_argnames, call_argvalues); } std::string BuiltinFunction::dump(const std::string &indent, const std::string &name) const { std::stringstream dump; dump << indent << "builtin function " << name << "();\n"; return dump.str(); } static double deg2rad(double x) { while (x < 0.0) x += 360.0; while (x >= 360.0) x -= 360.0; x = x * M_PI * 2.0 / 360.0; return x; } static double rad2deg(double x) { x = x * 360.0 / (M_PI * 2.0); while (x < 0.0) x += 360.0; while (x >= 360.0) x -= 360.0; return x; } Value builtin_abs(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(fabs(args[0].num)); return Value(); } Value builtin_sign(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value((args[0].num<0) ? -1.0 : ((args[0].num>0) ? 1.0 : 0.0)); return Value(); } double frand() { return rand()/(double(RAND_MAX)+1); } double frand(double min, double max) { return (min>max) ? frand()*(min-max)+max : frand()*(max-min)+min; } Value builtin_rands(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 3 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER && args[2].type == Value::NUMBER) { srand((unsigned int)time(0)); } else if (args.size() == 4 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER && args[2].type == Value::NUMBER && args[3].type == Value::NUMBER) { srand((unsigned int)args[3].num); } else { return Value(); } Value v; v.type = Value::VECTOR; for (int i=0; i&, const std::vector &args) { if (args.size() >= 1 && args[0].type == Value::NUMBER) { double val = args[0].num; for (size_t i = 1; i < args.size(); i++) if (args[1].type == Value::NUMBER) val = fmin(val, args[i].num); return Value(val); } return Value(); } Value builtin_max(const Context *, const std::vector&, const std::vector &args) { if (args.size() >= 1 && args[0].type == Value::NUMBER) { double val = args[0].num; for (size_t i = 1; i < args.size(); i++) if (args[1].type == Value::NUMBER) val = fmax(val, args[i].num); return Value(val); } return Value(); } Value builtin_sin(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(sin(deg2rad(args[0].num))); return Value(); } Value builtin_cos(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(cos(deg2rad(args[0].num))); return Value(); } Value builtin_asin(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(rad2deg(asin(args[0].num))); return Value(); } Value builtin_acos(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(rad2deg(acos(args[0].num))); return Value(); } Value builtin_tan(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(tan(deg2rad(args[0].num))); return Value(); } Value builtin_atan(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(rad2deg(atan(args[0].num))); return Value(); } Value builtin_atan2(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 2 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER) return Value(rad2deg(atan2(args[0].num, args[1].num))); return Value(); } Value builtin_pow(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 2 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER) return Value(pow(args[0].num, args[1].num)); return Value(); } Value builtin_round(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(round(args[0].num)); return Value(); } Value builtin_ceil(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(ceil(args[0].num)); return Value(); } Value builtin_floor(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(floor(args[0].num)); return Value(); } Value builtin_sqrt(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(sqrt(args[0].num)); return Value(); } Value builtin_exp(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(exp(args[0].num)); return Value(); } Value builtin_length(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1){ if (args[0].type == Value::VECTOR) return Value((double) args[0].vec.size()); if (args[0].type == Value::STRING) return Value((double) args[0].text.size()); } return Value(); } Value builtin_log(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 2 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER) return Value(log(args[1].num) / log(args[0].num)); if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(log(args[0].num) / log(10.0)); return Value(); } Value builtin_ln(const Context *, const std::vector&, const std::vector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(log(args[0].num)); return Value(); } Value builtin_str(const Context *, const std::vector&, const std::vector &args) { std::stringstream stream; for (size_t i = 0; i < args.size(); i++) { stream << args[i].toString(); } return Value(stream.str()); } Value builtin_lookup(const Context *, const std::vector&, const std::vector &args) { double p, low_p, low_v, high_p, high_v; if (args.size() < 2 || !args[0].getnum(p) || args[1].vec.size() < 2 || args[1].vec[0]->vec.size() < 2) return Value(); if (!args[1].vec[0]->getv2(low_p, low_v) || !args[1].vec[0]->getv2(high_p, high_v)) return Value(); for (size_t i = 1; i < args[1].vec.size(); i++) { double this_p, this_v; if (args[1].vec[i]->getv2(this_p, this_v)) { if (this_p <= p && (this_p > low_p || low_p > p)) { low_p = this_p; low_v = this_v; } if (this_p >= p && (this_p < high_p || high_p < p)) { high_p = this_p; high_v = this_v; } } } if (p <= low_p) return Value(low_v); if (p >= high_p) return Value(high_v); double f = (p-low_p) / (high_p-low_p); return Value(high_v * f + low_v * (1-f)); } #define QUOTE(x__) # x__ #define QUOTED(x__) QUOTE(x__) Value builtin_version(const Context *, const std::vector&, const std::vector &) { Value val; val.type = Value::VECTOR; val.append(new Value(double(OPENSCAD_YEAR))); val.append(new Value(double(OPENSCAD_MONTH))); #ifdef OPENSCAD_DAY val.append(new Value(double(OPENSCAD_DAY))); #endif return val; } Value builtin_version_num(const Context *ctx, const std::vector& call_argnames, const std::vector &args) { Value val = (args.size() == 0) ? builtin_version(ctx, call_argnames, args) : args[0]; double y, m, d = 0; if (!val.getv3(y, m, d)) { if (!val.getv2(y, m)) { return Value(); } } return Value(y * 10000 + m * 100 + d); } void register_builtin_functions() { Builtins::init("abs", new BuiltinFunction(&builtin_abs)); Builtins::init("sign", new BuiltinFunction(&builtin_sign)); Builtins::init("rands", new BuiltinFunction(&builtin_rands)); Builtins::init("min", new BuiltinFunction(&builtin_min)); Builtins::init("max", new BuiltinFunction(&builtin_max)); Builtins::init("sin", new BuiltinFunction(&builtin_sin)); Builtins::init("cos", new BuiltinFunction(&builtin_cos)); Builtins::init("asin", new BuiltinFunction(&builtin_asin)); Builtins::init("acos", new BuiltinFunction(&builtin_acos)); Builtins::init("tan", new BuiltinFunction(&builtin_tan)); Builtins::init("atan", new BuiltinFunction(&builtin_atan)); Builtins::init("atan2", new BuiltinFunction(&builtin_atan2)); Builtins::init("round", new BuiltinFunction(&builtin_round)); Builtins::init("ceil", new BuiltinFunction(&builtin_ceil)); Builtins::init("floor", new BuiltinFunction(&builtin_floor)); Builtins::init("pow", new BuiltinFunction(&builtin_pow)); Builtins::init("sqrt", new BuiltinFunction(&builtin_sqrt)); Builtins::init("exp", new BuiltinFunction(&builtin_exp)); Builtins::init("len", new BuiltinFunction(&builtin_length)); Builtins::init("log", new BuiltinFunction(&builtin_log)); Builtins::init("ln", new BuiltinFunction(&builtin_ln)); Builtins::init("str", new BuiltinFunction(&builtin_str)); Builtins::init("lookup", new BuiltinFunction(&builtin_lookup)); Builtins::init("version", new BuiltinFunction(&builtin_version)); Builtins::init("version_num", new BuiltinFunction(&builtin_version_num)); }