2009-06-20 23:00:19 +04:00
|
|
|
/*
|
2011-01-21 04:21:09 +03:00
|
|
|
* OpenSCAD (www.openscad.org)
|
|
|
|
* Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
|
|
|
|
* Marius Kintel <marius@kintel.net>
|
2009-06-20 23:00:19 +04:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
2010-02-01 12:34:18 +03:00
|
|
|
* 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.
|
|
|
|
*
|
2009-06-20 23:00:19 +04:00
|
|
|
* 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
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2010-01-30 07:26:05 +03:00
|
|
|
#include "function.h"
|
|
|
|
#include "expression.h"
|
|
|
|
#include "context.h"
|
|
|
|
#include "builtin.h"
|
2010-11-08 00:29:34 +03:00
|
|
|
#include <sstream>
|
2011-08-13 03:48:59 +04:00
|
|
|
#include <ctime>
|
2011-01-18 02:02:56 +03:00
|
|
|
#include "mathc99.h"
|
2011-09-03 08:10:36 +04:00
|
|
|
#include <algorithm>
|
|
|
|
#include "stl-utils.h"
|
2012-02-15 08:04:40 +04:00
|
|
|
#include "printutils.h"
|
2009-06-20 23:00:19 +04:00
|
|
|
|
|
|
|
AbstractFunction::~AbstractFunction()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value AbstractFunction::evaluate(const Context*, const std::vector<std::string>&, const std::vector<Value>&) const
|
2009-06-20 23:00:19 +04:00
|
|
|
{
|
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
std::string AbstractFunction::dump(const std::string &indent, const std::string &name) const
|
2009-06-21 10:53:46 +04:00
|
|
|
{
|
2011-09-03 08:10:36 +04:00
|
|
|
std::stringstream dump;
|
|
|
|
dump << indent << "abstract function " << name << "();\n";
|
|
|
|
return dump.str();
|
2009-06-21 10:53:46 +04:00
|
|
|
}
|
|
|
|
|
2009-06-20 23:00:19 +04:00
|
|
|
Function::~Function()
|
|
|
|
{
|
2011-09-03 08:10:36 +04:00
|
|
|
std::for_each(this->argexpr.begin(), this->argexpr.end(), del_fun<Expression>());
|
2009-06-21 10:53:46 +04:00
|
|
|
delete expr;
|
2009-06-20 23:00:19 +04:00
|
|
|
}
|
|
|
|
|
2011-09-03 20:51:29 +04:00
|
|
|
Value Function::evaluate(const Context *ctx,
|
|
|
|
const std::vector<std::string> &call_argnames,
|
|
|
|
const std::vector<Value> &call_argvalues) const
|
2009-06-20 23:00:19 +04:00
|
|
|
{
|
|
|
|
Context c(ctx);
|
|
|
|
c.args(argnames, argexpr, call_argnames, call_argvalues);
|
2009-06-21 10:53:46 +04:00
|
|
|
if (expr)
|
|
|
|
return expr->evaluate(&c);
|
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
std::string Function::dump(const std::string &indent, const std::string &name) const
|
2009-06-21 10:53:46 +04:00
|
|
|
{
|
2011-09-03 08:10:36 +04:00
|
|
|
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];
|
2009-06-21 10:53:46 +04:00
|
|
|
}
|
2011-09-03 08:10:36 +04:00
|
|
|
dump << ") = " << *expr << ";\n";
|
|
|
|
return dump.str();
|
2009-06-20 23:00:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinFunction::~BuiltinFunction()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value BuiltinFunction::evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const
|
2009-06-20 23:00:19 +04:00
|
|
|
{
|
2010-02-23 23:47:54 +03:00
|
|
|
return eval_func(ctx, call_argnames, call_argvalues);
|
2009-06-20 23:00:19 +04:00
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
std::string BuiltinFunction::dump(const std::string &indent, const std::string &name) const
|
2009-06-21 10:53:46 +04:00
|
|
|
{
|
2011-09-03 08:10:36 +04:00
|
|
|
std::stringstream dump;
|
|
|
|
dump << indent << "builtin function " << name << "();\n";
|
|
|
|
return dump.str();
|
2009-06-21 10:53:46 +04:00
|
|
|
}
|
|
|
|
|
2012-01-08 21:31:09 +04:00
|
|
|
static inline double deg2rad(double x)
|
2009-06-30 22:05:10 +04:00
|
|
|
{
|
2012-01-08 21:31:09 +04:00
|
|
|
return x * M_PI / 180.0;
|
2009-06-30 22:05:10 +04:00
|
|
|
}
|
|
|
|
|
2012-01-08 21:31:09 +04:00
|
|
|
static inline double rad2deg(double x)
|
2009-06-30 22:05:10 +04:00
|
|
|
{
|
2012-01-08 21:31:09 +04:00
|
|
|
return x * 180.0 / M_PI;
|
2009-06-30 22:05:10 +04:00
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_abs(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-02-26 14:53:32 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(fabs(args[0].toDouble()));
|
2010-02-26 14:53:32 +03:00
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_sign(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-07-09 13:35:19 +04:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value((args[0].toDouble()<0) ? -1.0 : ((args[0].toDouble()>0) ? 1.0 : 0.0));
|
2010-07-09 13:35:19 +04:00
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2010-10-31 05:51:11 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_rands(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-10-31 05:51:11 +03:00
|
|
|
{
|
2010-10-31 05:51:27 +03:00
|
|
|
if (args.size() == 3 &&
|
2012-03-28 02:05:00 +04:00
|
|
|
args[0].type() == Value::NUMBER &&
|
|
|
|
args[1].type() == Value::NUMBER &&
|
|
|
|
args[2].type() == Value::NUMBER)
|
2010-10-31 05:51:11 +03:00
|
|
|
{
|
|
|
|
srand((unsigned int)time(0));
|
|
|
|
}
|
2010-10-31 05:51:27 +03:00
|
|
|
else if (args.size() == 4 &&
|
2012-03-28 02:05:00 +04:00
|
|
|
args[0].type() == Value::NUMBER &&
|
|
|
|
args[1].type() == Value::NUMBER &&
|
|
|
|
args[2].type() == Value::NUMBER &&
|
|
|
|
args[3].type() == Value::NUMBER)
|
2010-10-31 05:51:11 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
srand((unsigned int)args[3].toDouble());
|
2010-10-31 05:51:11 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return Value();
|
|
|
|
}
|
2010-10-31 05:51:27 +03:00
|
|
|
|
2012-03-28 02:05:00 +04:00
|
|
|
Value::VectorType vec;
|
|
|
|
for (int i=0; i<args[2].toDouble(); i++) {
|
|
|
|
vec.push_back(Value(frand(args[0].toDouble(), args[1].toDouble())));
|
2010-10-31 05:51:11 +03:00
|
|
|
}
|
2010-10-31 05:51:27 +03:00
|
|
|
|
2012-03-28 02:05:00 +04:00
|
|
|
return Value(vec);
|
2010-10-31 05:51:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_min(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-01-06 22:58:54 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() >= 1 && args[0].type() == Value::NUMBER) {
|
|
|
|
double val = args[0].toDouble();
|
2011-09-03 08:10:36 +04:00
|
|
|
for (size_t i = 1; i < args.size(); i++)
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args[1].type() == Value::NUMBER)
|
|
|
|
val = fmin(val, args[i].toDouble());
|
2010-01-06 22:58:54 +03:00
|
|
|
return Value(val);
|
|
|
|
}
|
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_max(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-01-06 22:58:54 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() >= 1 && args[0].type() == Value::NUMBER) {
|
|
|
|
double val = args[0].toDouble();
|
2011-09-03 08:10:36 +04:00
|
|
|
for (size_t i = 1; i < args.size(); i++)
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args[1].type() == Value::NUMBER)
|
|
|
|
val = fmax(val, args[i].toDouble());
|
2010-01-06 22:58:54 +03:00
|
|
|
return Value(val);
|
|
|
|
}
|
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_sin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2009-06-20 23:00:19 +04:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(sin(deg2rad(args[0].toDouble())));
|
2009-06-23 14:31:25 +04:00
|
|
|
return Value();
|
2009-06-20 23:00:19 +04:00
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_cos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2009-06-20 23:00:19 +04:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(cos(deg2rad(args[0].toDouble())));
|
2009-06-23 14:31:25 +04:00
|
|
|
return Value();
|
2009-06-20 23:00:19 +04:00
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_asin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2009-06-20 23:00:19 +04:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(rad2deg(asin(args[0].toDouble())));
|
2009-06-23 14:31:25 +04:00
|
|
|
return Value();
|
2009-06-20 23:00:19 +04:00
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_acos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2009-06-20 23:00:19 +04:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(rad2deg(acos(args[0].toDouble())));
|
2009-06-23 14:31:25 +04:00
|
|
|
return Value();
|
2009-06-20 23:00:19 +04:00
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_tan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2009-06-20 23:00:19 +04:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(tan(deg2rad(args[0].toDouble())));
|
2009-06-23 14:31:25 +04:00
|
|
|
return Value();
|
2009-06-20 23:00:19 +04:00
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_atan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2009-06-20 23:00:19 +04:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(rad2deg(atan(args[0].toDouble())));
|
2009-06-23 14:31:25 +04:00
|
|
|
return Value();
|
2009-06-20 23:00:19 +04:00
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_atan2(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2009-06-20 23:00:19 +04:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER)
|
|
|
|
return Value(rad2deg(atan2(args[0].toDouble(), args[1].toDouble())));
|
2009-06-23 14:31:25 +04:00
|
|
|
return Value();
|
2009-06-20 23:00:19 +04:00
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_pow(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-01-31 04:42:17 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER)
|
|
|
|
return Value(pow(args[0].toDouble(), args[1].toDouble()));
|
2010-01-31 04:42:17 +03:00
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_round(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-01-31 04:42:17 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(round(args[0].toDouble()));
|
2010-01-31 04:42:17 +03:00
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_ceil(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-01-31 04:42:17 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(ceil(args[0].toDouble()));
|
2010-01-31 04:42:17 +03:00
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_floor(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-02-21 11:16:09 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(floor(args[0].toDouble()));
|
2010-02-21 11:16:09 +03:00
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_sqrt(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-02-10 20:27:08 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(sqrt(args[0].toDouble()));
|
2010-02-10 20:27:08 +03:00
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_exp(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-02-21 11:16:09 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(exp(args[0].toDouble()));
|
2010-02-21 11:16:09 +03:00
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-11-12 23:42:27 +04:00
|
|
|
Value builtin_length(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1) {
|
|
|
|
if (args[0].type() == Value::VECTOR) return Value(int(args[0].toVector().size()));
|
|
|
|
if (args[0].type() == Value::STRING) return Value(int(args[0].toString().size()));
|
2011-11-12 23:42:27 +04:00
|
|
|
}
|
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_log(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-02-21 11:16:09 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER)
|
|
|
|
return Value(log(args[1].toDouble()) / log(args[0].toDouble()));
|
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(log(args[0].toDouble()) / log(10.0));
|
2010-02-21 11:16:09 +03:00
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_ln(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-02-21 11:16:09 +03:00
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() == 1 && args[0].type() == Value::NUMBER)
|
|
|
|
return Value(log(args[0].toDouble()));
|
2010-02-21 11:16:09 +03:00
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_str(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2009-11-26 14:54:28 +03:00
|
|
|
{
|
2010-11-08 00:29:34 +03:00
|
|
|
std::stringstream stream;
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
for (size_t i = 0; i < args.size(); i++) {
|
2011-11-09 21:38:52 +04:00
|
|
|
stream << args[i].toString();
|
2009-11-26 14:54:28 +03:00
|
|
|
}
|
2010-11-08 00:29:34 +03:00
|
|
|
return Value(stream.str());
|
2009-11-26 14:54:28 +03:00
|
|
|
}
|
|
|
|
|
2011-09-03 08:10:36 +04:00
|
|
|
Value builtin_lookup(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
2010-01-13 20:03:32 +03:00
|
|
|
{
|
|
|
|
double p, low_p, low_v, high_p, high_v;
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args.size() < 2 || // Needs two args
|
|
|
|
!args[0].getDouble(p) || // First must be a number
|
|
|
|
args[1].toVector().size() < 2 || // Second must be a vector of vectors
|
|
|
|
args[1].toVector()[0].toVector().size() < 2)
|
2010-01-13 20:03:32 +03:00
|
|
|
return Value();
|
2012-03-28 02:05:00 +04:00
|
|
|
if (!args[1].toVector()[0].getVec2(low_p, low_v) || !args[1].toVector()[0].getVec2(high_p, high_v))
|
2010-01-13 20:03:32 +03:00
|
|
|
return Value();
|
2012-03-28 02:05:00 +04:00
|
|
|
for (size_t i = 1; i < args[1].toVector().size(); i++) {
|
2010-01-13 20:03:32 +03:00
|
|
|
double this_p, this_v;
|
2012-03-28 02:05:00 +04:00
|
|
|
if (args[1].toVector()[i].getVec2(this_p, this_v)) {
|
2010-01-13 20:03:32 +03:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2012-02-15 08:04:40 +04:00
|
|
|
/*
|
|
|
|
Pattern:
|
|
|
|
|
|
|
|
"search" "(" ( match_value | list_of_match_values ) "," vector_of_vectors
|
|
|
|
("," num_returns_per_match
|
|
|
|
("," index_col_num )? )?
|
|
|
|
")";
|
|
|
|
match_value : ( Value::NUMBER | Value::STRING );
|
|
|
|
list_of_values : "[" match_value ("," match_value)* "]";
|
|
|
|
vector_of_vectors : "[" ("[" Value ("," Value)* "]")+ "]";
|
|
|
|
num_returns_per_match : int;
|
|
|
|
index_col_num : int;
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
Index values return as list:
|
|
|
|
search("a","abcdabcd");
|
|
|
|
- returns [0,4]
|
|
|
|
search("a","abcdabcd",1);
|
|
|
|
- returns [0]
|
|
|
|
search("e","abcdabcd",1);
|
|
|
|
- returns []
|
|
|
|
search("a",[ ["a",1],["b",2],["c",3],["d",4],["a",5],["b",6],["c",7],["d",8],["e",9] ]);
|
|
|
|
- returns [0,4]
|
|
|
|
|
|
|
|
Search on different column; return Index values:
|
|
|
|
search(3,[ ["a",1],["b",2],["c",3],["d",4],["a",5],["b",6],["c",7],["d",8],["e",3] ], 0, 1);
|
|
|
|
- returns [0,8]
|
|
|
|
|
|
|
|
Search on list of values:
|
|
|
|
Return all matches per search vector element:
|
|
|
|
search("abc",[ ["a",1],["b",2],["c",3],["d",4],["a",5],["b",6],["c",7],["d",8],["e",9] ], 0);
|
|
|
|
- returns [[0,4],[1,5],[2,6]]
|
|
|
|
|
|
|
|
Return first match per search vector element; special case return vector:
|
|
|
|
search("abc",[ ["a",1],["b",2],["c",3],["d",4],["a",5],["b",6],["c",7],["d",8],["e",9] ], 1);
|
|
|
|
- returns [0,1,2]
|
|
|
|
|
|
|
|
Return first two matches per search vector element; vector of vectors:
|
|
|
|
search("abce",[ ["a",1],["b",2],["c",3],["d",4],["a",5],["b",6],["c",7],["d",8],["e",9] ], 2);
|
|
|
|
- returns [[0,4],[1,5],[2,6],[8]]
|
|
|
|
|
|
|
|
*/
|
|
|
|
Value builtin_search(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
|
|
|
|
{
|
2012-02-18 16:44:24 +04:00
|
|
|
if (args.size() < 2) return Value();
|
|
|
|
|
|
|
|
const Value &findThis = args[0];
|
|
|
|
const Value &searchTable = args[1];
|
2012-03-28 02:05:00 +04:00
|
|
|
unsigned int num_returns_per_match = (args.size() > 2) ? args[2].toDouble() : 1;
|
|
|
|
unsigned int index_col_num = (args.size() > 3) ? args[3].toDouble() : 0;
|
2012-02-18 16:44:24 +04:00
|
|
|
|
2012-03-28 02:05:00 +04:00
|
|
|
Value::VectorType returnvec;
|
2012-02-18 16:44:24 +04:00
|
|
|
|
2012-03-28 02:05:00 +04:00
|
|
|
if (findThis.type() == Value::NUMBER) {
|
2012-02-18 16:44:24 +04:00
|
|
|
unsigned int matchCount = 0;
|
2012-03-28 02:05:00 +04:00
|
|
|
Value::VectorType resultvec;
|
|
|
|
for (size_t j = 0; j < searchTable.toVector().size(); j++) {
|
|
|
|
if (searchTable.toVector()[j].toVector()[index_col_num].type() == Value::NUMBER &&
|
|
|
|
findThis.toDouble() == searchTable.toVector()[j].toVector()[index_col_num].toDouble()) {
|
|
|
|
returnvec.push_back(Value(double(j)));
|
2012-02-15 08:04:40 +04:00
|
|
|
matchCount++;
|
2012-02-18 16:44:24 +04:00
|
|
|
if (num_returns_per_match != 0 && matchCount >= num_returns_per_match) break;
|
2012-02-15 08:04:40 +04:00
|
|
|
}
|
|
|
|
}
|
2012-03-28 02:05:00 +04:00
|
|
|
} else if (findThis.type() == Value::STRING) {
|
2012-02-15 08:04:40 +04:00
|
|
|
unsigned int searchTableSize;
|
2012-03-28 02:05:00 +04:00
|
|
|
if (searchTable.type() == Value::STRING) searchTableSize = searchTable.toString().size();
|
|
|
|
else searchTableSize = searchTable.toVector().size();
|
|
|
|
for (size_t i = 0; i < findThis.toString().size(); i++) {
|
2012-02-18 16:44:24 +04:00
|
|
|
unsigned int matchCount = 0;
|
2012-03-28 02:05:00 +04:00
|
|
|
Value::VectorType resultvec;
|
2012-02-15 08:04:40 +04:00
|
|
|
for (size_t j = 0; j < searchTableSize; j++) {
|
2012-03-28 02:05:00 +04:00
|
|
|
if ((searchTable.type() == Value::VECTOR &&
|
|
|
|
findThis.toString()[i] == searchTable.toVector()[j].toVector()[index_col_num].toString()[0]) ||
|
|
|
|
(searchTable.type() == Value::STRING &&
|
|
|
|
findThis.toString()[i] == searchTable.toString()[j])) {
|
|
|
|
Value resultValue((double(j)));
|
2012-02-15 08:04:40 +04:00
|
|
|
matchCount++;
|
2012-03-28 02:05:00 +04:00
|
|
|
if (num_returns_per_match == 1) {
|
|
|
|
returnvec.push_back(resultValue);
|
2012-02-18 16:44:24 +04:00
|
|
|
break;
|
2012-02-15 08:04:40 +04:00
|
|
|
} else {
|
2012-03-28 02:05:00 +04:00
|
|
|
resultvec.push_back(resultValue);
|
2012-02-15 08:04:40 +04:00
|
|
|
}
|
2012-02-18 16:44:24 +04:00
|
|
|
if (num_returns_per_match > 1 && matchCount >= num_returns_per_match) break;
|
2012-02-15 08:04:40 +04:00
|
|
|
}
|
|
|
|
}
|
2012-03-28 02:05:00 +04:00
|
|
|
if (matchCount == 0) PRINTB(" search term not found: \"%s\"", findThis.toString()[i]);
|
2012-02-18 16:44:24 +04:00
|
|
|
if (num_returns_per_match == 0 || num_returns_per_match > 1) {
|
2012-03-28 02:05:00 +04:00
|
|
|
returnvec.push_back(Value(resultvec));
|
2012-02-18 16:44:24 +04:00
|
|
|
}
|
2012-02-15 08:04:40 +04:00
|
|
|
}
|
2012-03-28 02:05:00 +04:00
|
|
|
} else if (findThis.type() == Value::VECTOR) {
|
|
|
|
for (size_t i = 0; i < findThis.toVector().size(); i++) {
|
2012-02-18 16:44:24 +04:00
|
|
|
unsigned int matchCount = 0;
|
2012-03-28 02:05:00 +04:00
|
|
|
Value::VectorType resultvec;
|
|
|
|
for (size_t j = 0; j < searchTable.toVector().size(); j++) {
|
|
|
|
if ((findThis.toVector()[i].type() == Value::NUMBER &&
|
|
|
|
searchTable.toVector()[j].toVector()[index_col_num].type() == Value::NUMBER &&
|
|
|
|
findThis.toVector()[i].toDouble() == searchTable.toVector()[j].toVector()[index_col_num].toDouble()) ||
|
|
|
|
(findThis.toVector()[i].type() == Value::STRING &&
|
|
|
|
searchTable.toVector()[j].toVector()[index_col_num].type() == Value::STRING &&
|
|
|
|
findThis.toVector()[i].toString() == searchTable.toVector()[j].toVector()[index_col_num].toString())) {
|
|
|
|
Value resultValue((double(j)));
|
2012-02-15 08:04:40 +04:00
|
|
|
matchCount++;
|
2012-03-28 02:05:00 +04:00
|
|
|
if (num_returns_per_match == 1) {
|
|
|
|
returnvec.push_back(resultValue);
|
2012-02-18 16:44:24 +04:00
|
|
|
break;
|
2012-02-15 08:04:40 +04:00
|
|
|
} else {
|
2012-03-28 02:05:00 +04:00
|
|
|
resultvec.push_back(resultValue);
|
2012-02-15 08:04:40 +04:00
|
|
|
}
|
2012-02-18 16:44:24 +04:00
|
|
|
if (num_returns_per_match > 1 && matchCount >= num_returns_per_match) break;
|
2012-02-15 08:04:40 +04:00
|
|
|
}
|
|
|
|
}
|
2012-02-18 16:44:24 +04:00
|
|
|
if (num_returns_per_match == 1 && matchCount == 0) {
|
2012-03-28 02:05:00 +04:00
|
|
|
if (findThis.toVector()[i].type() == Value::NUMBER) {
|
|
|
|
PRINTB(" search term not found: %s",findThis.toVector()[i].toDouble());
|
2012-02-18 16:44:24 +04:00
|
|
|
}
|
2012-03-28 02:05:00 +04:00
|
|
|
else if (findThis.toVector()[i].type() == Value::STRING) {
|
|
|
|
PRINTB(" search term not found: \"%s\"",findThis.toVector()[i].toString());
|
2012-02-18 16:44:24 +04:00
|
|
|
}
|
2012-03-28 02:05:00 +04:00
|
|
|
returnvec.push_back(Value(resultvec));
|
2012-02-15 08:04:40 +04:00
|
|
|
}
|
2012-02-18 16:44:24 +04:00
|
|
|
if (num_returns_per_match == 0 || num_returns_per_match > 1) {
|
2012-03-28 02:05:00 +04:00
|
|
|
returnvec.push_back(Value(resultvec));
|
2012-02-18 16:44:24 +04:00
|
|
|
}
|
2012-02-15 08:04:40 +04:00
|
|
|
}
|
|
|
|
} else {
|
2012-02-18 16:44:24 +04:00
|
|
|
PRINTB(" search: none performed on input %s", findThis);
|
2012-02-15 08:04:40 +04:00
|
|
|
return Value();
|
|
|
|
}
|
2012-03-28 02:05:00 +04:00
|
|
|
return Value(returnvec);
|
2012-02-15 08:04:40 +04:00
|
|
|
}
|
|
|
|
|
2011-09-30 04:43:09 +04:00
|
|
|
#define QUOTE(x__) # x__
|
|
|
|
#define QUOTED(x__) QUOTE(x__)
|
|
|
|
|
|
|
|
Value builtin_version(const Context *, const std::vector<std::string>&, const std::vector<Value> &)
|
|
|
|
{
|
2012-03-28 02:05:00 +04:00
|
|
|
Value::VectorType val;
|
|
|
|
val.push_back(Value(double(OPENSCAD_YEAR)));
|
|
|
|
val.push_back(Value(double(OPENSCAD_MONTH)));
|
2011-10-04 02:09:04 +04:00
|
|
|
#ifdef OPENSCAD_DAY
|
2012-03-28 02:05:00 +04:00
|
|
|
val.push_back(Value(double(OPENSCAD_DAY)));
|
2011-10-04 02:09:04 +04:00
|
|
|
#endif
|
2012-03-28 02:05:00 +04:00
|
|
|
return Value(val);
|
2011-10-04 02:09:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
Value builtin_version_num(const Context *ctx, const std::vector<std::string>& call_argnames, const std::vector<Value> &args)
|
|
|
|
{
|
|
|
|
Value val = (args.size() == 0) ? builtin_version(ctx, call_argnames, args) : args[0];
|
|
|
|
double y, m, d = 0;
|
2012-03-28 02:05:00 +04:00
|
|
|
if (!val.getVec3(y, m, d)) {
|
|
|
|
if (!val.getVec2(y, m)) {
|
2011-10-04 02:09:04 +04:00
|
|
|
return Value();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Value(y * 10000 + m * 100 + d);
|
2011-09-30 04:43:09 +04:00
|
|
|
}
|
|
|
|
|
2011-11-06 21:37:12 +04:00
|
|
|
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));
|
2011-11-12 23:42:27 +04:00
|
|
|
Builtins::init("len", new BuiltinFunction(&builtin_length));
|
2011-11-06 21:37:12 +04:00
|
|
|
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));
|
2012-02-15 08:04:40 +04:00
|
|
|
Builtins::init("search", new BuiltinFunction(&builtin_search));
|
2011-11-06 21:37:12 +04:00
|
|
|
Builtins::init("version", new BuiltinFunction(&builtin_version));
|
|
|
|
Builtins::init("version_num", new BuiltinFunction(&builtin_version_num));
|
2009-06-20 23:00:19 +04:00
|
|
|
}
|