diff options
author | Marius Kintel <marius@kintel.net> | 2012-03-27 22:05:00 (GMT) |
---|---|---|
committer | Marius Kintel <marius@kintel.net> | 2012-03-27 22:05:58 (GMT) |
commit | 327310f190bbd81c7b71b568d5bf72bb900cc9db (patch) | |
tree | 9399bb490ecafe9f0c7fd209c680311d829eb631 /src | |
parent | 4394c7a030ce7a08c95bd1af2e8c38ffcf972439 (diff) |
Rewrote the Value class to be based on boost::variant - this should reduce memory footprint and improve performance
Diffstat (limited to 'src')
-rw-r--r-- | src/cgaladv.cc | 6 | ||||
-rw-r--r-- | src/color.cc | 12 | ||||
-rw-r--r-- | src/context.cc | 14 | ||||
-rw-r--r-- | src/control.cc | 28 | ||||
-rw-r--r-- | src/dxfdim.cc | 27 | ||||
-rw-r--r-- | src/expr.cc | 80 | ||||
-rw-r--r-- | src/expression.h | 4 | ||||
-rw-r--r-- | src/func.cc | 244 | ||||
-rw-r--r-- | src/import.cc | 26 | ||||
-rw-r--r-- | src/linearextrude.cc | 32 | ||||
-rw-r--r-- | src/mainwin.cc | 22 | ||||
-rw-r--r-- | src/parser.y | 31 | ||||
-rw-r--r-- | src/primitives.cc | 84 | ||||
-rw-r--r-- | src/projection.cc | 6 | ||||
-rw-r--r-- | src/render.cc | 4 | ||||
-rw-r--r-- | src/rotateextrude.cc | 18 | ||||
-rw-r--r-- | src/surface.cc | 11 | ||||
-rw-r--r-- | src/transform.cc | 32 | ||||
-rw-r--r-- | src/value.cc | 1000 | ||||
-rw-r--r-- | src/value.h | 149 |
20 files changed, 955 insertions, 875 deletions
diff --git a/src/cgaladv.cc b/src/cgaladv.cc index 9abf87c..1773a90 100644 --- a/src/cgaladv.cc +++ b/src/cgaladv.cc @@ -78,10 +78,10 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat level = c.lookup_variable("level", true); } - node->convexity = (int)convexity.num; + node->convexity = (int)convexity.toDouble(); node->path = path; - node->subdiv_type = subdiv_type.text; - node->level = (int)level.num; + node->subdiv_type = subdiv_type.toString(); + node->level = (int)level.toDouble(); if (node->level <= 1) node->level = 1; diff --git a/src/color.cc b/src/color.cc index e458bfb..4220396 100644 --- a/src/color.cc +++ b/src/color.cc @@ -63,11 +63,11 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio c.args(argnames, argexpr, inst->argnames, inst->argvalues); Value v = c.lookup_variable("c"); - if (v.type == Value::VECTOR) { + if (v.type() == Value::VECTOR) { for (size_t i = 0; i < 4; i++) - node->color[i] = i < v.vec.size() ? v.vec[i]->num : 1.0; - } else if (v.type == Value::STRING) { - std::string colorname = v.text; + node->color[i] = i < v.toVector().size() ? v.toVector()[i].toDouble() : 1.0; + } else if (v.type() == Value::STRING) { + std::string colorname = v.toString(); boost::algorithm::to_lower(colorname); Color4f color; if (colormap.find(colorname) != colormap.end()) { @@ -81,8 +81,8 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio } } Value alpha = c.lookup_variable("alpha"); - if (alpha.type == Value::NUMBER) { - node->color[3] = alpha.num; + if (alpha.type() == Value::NUMBER) { + node->color[3] = alpha.toDouble(); } std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); diff --git a/src/context.cc b/src/context.cc index f96a45b..2decc48 100644 --- a/src/context.cc +++ b/src/context.cc @@ -196,13 +196,13 @@ void register_builtin(Context &ctx) ctx.set_variable("$fa", Value(12.0)); ctx.set_variable("$t", Value(0.0)); - Value zero3; - zero3.type = Value::VECTOR; - zero3.append(new Value(0.0)); - zero3.append(new Value(0.0)); - zero3.append(new Value(0.0)); - ctx.set_variable("$vpt", zero3); - ctx.set_variable("$vpr", zero3); + Value::VectorType zero3; + zero3.push_back(Value(0.0)); + zero3.push_back(Value(0.0)); + zero3.push_back(Value(0.0)); + Value zero3val(zero3); + ctx.set_variable("$vpt", zero3val); + ctx.set_variable("$vpr", zero3val); ctx.set_constant("PI",Value(M_PI)); } diff --git a/src/control.cc b/src/control.cc index 1d87551..bdd0f40 100644 --- a/src/control.cc +++ b/src/control.cc @@ -57,29 +57,27 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l, const std::string &it_name = call_argnames[l]; const Value &it_values = call_argvalues[l]; Context c(arg_context); - if (it_values.type == Value::RANGE) { - double range_begin = it_values.range_begin; - double range_end = it_values.range_end; - double range_step = it_values.range_step; - if (range_end < range_begin) { - double t = range_begin; - range_begin = range_end; - range_end = t; + if (it_values.type() == Value::RANGE) { + Value::RangeType range = it_values.toRange(); + if (range.end < range.begin) { + double t = range.begin; + range.begin = range.end; + range.end = t; } - if (range_step > 0 && (range_begin-range_end)/range_step < 10000) { - for (double i = range_begin; i <= range_end; i += range_step) { + if (range.step > 0 && (range.begin-range.end)/range.step < 10000) { + for (double i = range.begin; i <= range.end; i += range.step) { c.set_variable(it_name, Value(i)); for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); } } } - else if (it_values.type == Value::VECTOR) { - for (size_t i = 0; i < it_values.vec.size(); i++) { - c.set_variable(it_name, *it_values.vec[i]); + else if (it_values.type() == Value::VECTOR) { + for (size_t i = 0; i < it_values.toVector().size(); i++) { + c.set_variable(it_name, it_values.toVector()[i]); for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); } } - else if (it_values.type != Value::UNDEFINED) { + else if (it_values.type() != Value::UNDEFINED) { c.set_variable(it_name, it_values); for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); } @@ -98,7 +96,7 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation size_t n = 0; if (inst->argvalues.size() > 0) { double v; - if (inst->argvalues[0].getnum(v)) + if (inst->argvalues[0].getDouble(v)) n = v; } for (int i = Context::ctx_stack.size()-1; i >= 0; i--) { diff --git a/src/dxfdim.cc b/src/dxfdim.cc index 664fdb5..8f68ac6 100644 --- a/src/dxfdim.cc +++ b/src/dxfdim.cc @@ -52,15 +52,15 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam for (size_t i = 0; i < argnames.size() && i < args.size(); i++) { if (argnames[i] == "file") - filename = ctx->getAbsolutePath(args[i].text); + filename = ctx->getAbsolutePath(args[i].toString()); if (argnames[i] == "layer") - layername = args[i].text; + layername = args[i].toString(); if (argnames[i] == "origin") - args[i].getv2(xorigin, yorigin); + args[i].getVec2(xorigin, yorigin); if (argnames[i] == "scale") - args[i].getnum(scale); + args[i].getDouble(scale); if (argnames[i] == "name") - name = args[i].text; + name = args[i].toString(); } std::stringstream keystream; @@ -136,13 +136,13 @@ Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argn for (size_t i = 0; i < argnames.size() && i < args.size(); i++) { if (argnames[i] == "file") - filename = ctx->getAbsolutePath(args[i].text); + filename = ctx->getAbsolutePath(args[i].toString()); if (argnames[i] == "layer") - layername = args[i].text; + layername = args[i].toString(); if (argnames[i] == "origin") - args[i].getv2(xorigin, yorigin); + args[i].getVec2(xorigin, yorigin); if (argnames[i] == "scale") - args[i].getnum(scale); + args[i].getDouble(scale); } std::stringstream keystream; @@ -178,11 +178,10 @@ Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argn // double ub = ((x2 - x1)*(y1 - y3) - (y2 - y1)*(x1 - x3)) / dem; double x = x1 + ua*(x2 - x1); double y = y1 + ua*(y2 - y1); - Value ret; - ret.type = Value::VECTOR; - ret.append(new Value(x)); - ret.append(new Value(y)); - return dxf_cross_cache[key] = ret; + Value::VectorType ret; + ret.push_back(Value(x)); + ret.push_back(Value(y)); + return dxf_cross_cache[key] = Value(ret); } } diff --git a/src/expr.cc b/src/expr.cc index 671553c..75fc47a 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -31,16 +31,20 @@ #include <sstream> #include <algorithm> #include "stl-utils.h" +#include <boost/bind.hpp> +#include <boost/foreach.hpp> Expression::Expression() { - this->const_value = NULL; +} + +Expression::Expression(const Value &val) : const_value(val), type("C") +{ } Expression::~Expression() { std::for_each(this->children.begin(), this->children.end(), del_fun<Expression>()); - delete this->const_value; } Value Expression::evaluate(const Context *context) const @@ -78,44 +82,27 @@ Value Expression::evaluate(const Context *context) const return this->children[v.toBool() ? 1 : 2]->evaluate(context); } if (this->type == "[]") { - Value v1 = this->children[0]->evaluate(context); - Value v2 = this->children[1]->evaluate(context); - if (v1.type == Value::VECTOR && v2.type == Value::NUMBER) { - int i = int(v2.num); - if (i >= 0 && i < int(v1.vec.size())) - return *v1.vec[i]; - } - if (v1.type == Value::STRING && v2.type == Value::NUMBER) { - unsigned int i = int(v2.num); - if (i < v1.text.size()) - return Value(v1.text.substr(i, 1)); - } - return Value(); + return this->children[0]->evaluate(context)[this->children[1]->evaluate(context)]; } if (this->type == "I") - return this->children[0]->evaluate(context).inv(); + return -this->children[0]->evaluate(context); if (this->type == "C") - return *this->const_value; + return this->const_value; if (this->type == "R") { Value v1 = this->children[0]->evaluate(context); Value v2 = this->children[1]->evaluate(context); Value v3 = this->children[2]->evaluate(context); - if (v1.type == Value::NUMBER && v2.type == Value::NUMBER && v3.type == Value::NUMBER) { - Value r = Value(); - r.type = Value::RANGE; - r.range_begin = v1.num; - r.range_step = v2.num; - r.range_end = v3.num; - return r; + if (v1.type() == Value::NUMBER && v2.type() == Value::NUMBER && v3.type() == Value::NUMBER) { + return Value(v1.toDouble(), v2.toDouble(), v3.toDouble()); } return Value(); } if (this->type == "V") { - Value v; - v.type = Value::VECTOR; - for (size_t i = 0; i < this->children.size(); i++) - v.append(new Value(this->children[i]->evaluate(context))); - return v; + Value::VectorType vec; + BOOST_FOREACH(const Expression *e, this->children) { + vec.push_back(e->evaluate(context)); + } + return Value(vec); } if (this->type == "L") return context->lookup_variable(this->var_name); @@ -123,26 +110,29 @@ Value Expression::evaluate(const Context *context) const { Value v = this->children[0]->evaluate(context); - if (v.type == Value::VECTOR && this->var_name == "x") - return *v.vec[0]; - if (v.type == Value::VECTOR && this->var_name == "y") - return *v.vec[1]; - if (v.type == Value::VECTOR && this->var_name == "z") - return *v.vec[2]; + if (v.type() == Value::VECTOR && this->var_name == "x") + return v[0]; + if (v.type() == Value::VECTOR && this->var_name == "y") + return v[1]; + if (v.type() == Value::VECTOR && this->var_name == "z") + return v[2]; - if (v.type == Value::RANGE && this->var_name == "begin") - return Value(v.range_begin); - if (v.type == Value::RANGE && this->var_name == "step") - return Value(v.range_step); - if (v.type == Value::RANGE && this->var_name == "end") - return Value(v.range_end); + if (v.type() == Value::RANGE && this->var_name == "begin") + return Value(v[0]); + if (v.type() == Value::RANGE && this->var_name == "step") + return Value(v[1]); + if (v.type() == Value::RANGE && this->var_name == "end") + return Value(v[2]); return Value(); } if (this->type == "F") { - std::vector<Value> argvalues; - for (size_t i=0; i < this->children.size(); i++) - argvalues.push_back(this->children[i]->evaluate(context)); + Value::VectorType argvalues; + std::transform(this->children.begin(), this->children.end(), + std::back_inserter(argvalues), + boost::bind(&Expression::evaluate, _1, context)); + // for (size_t i=0; i < this->children.size(); i++) + // argvalues.push_back(this->children[i]->evaluate(context)); return context->evaluate_function(this->call_funcname, this->call_argnames, argvalues); } abort(); @@ -167,7 +157,7 @@ std::string Expression::toString() const stream << "(-" << *this->children[0] << ")"; } else if (this->type == "C") { - stream << *this->const_value; + stream << this->const_value; } else if (this->type == "R") { stream << "[" << *this->children[0] << " : " << *this->children[1] << " : " << this->children[2] << "]"; diff --git a/src/expression.h b/src/expression.h index acbd6aa..2919b78 100644 --- a/src/expression.h +++ b/src/expression.h @@ -3,13 +3,14 @@ #include <string> #include <vector> +#include "value.h" class Expression { public: std::vector<Expression*> children; - class Value *const_value; + const Value const_value; std::string var_name; std::string call_funcname; @@ -31,6 +32,7 @@ public: std::string type; Expression(); + Expression(const Value &val); ~Expression(); Value evaluate(const class Context *context) const; diff --git a/src/func.cc b/src/func.cc index 0c9b450..6c5f070 100644 --- a/src/func.cc +++ b/src/func.cc @@ -109,15 +109,15 @@ static inline double rad2deg(double x) Value builtin_abs(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(fabs(args[0].num)); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(fabs(args[0].toDouble())); return Value(); } Value builtin_sign(const Context *, const std::vector<std::string>&, const std::vector<Value> &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)); + 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)); return Value(); } @@ -134,45 +134,41 @@ double frand(double min, double max) Value builtin_rands(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { if (args.size() == 3 && - args[0].type == Value::NUMBER && - args[1].type == Value::NUMBER && - args[2].type == Value::NUMBER) + 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) + 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); + srand((unsigned int)args[3].toDouble()); } else { return Value(); } - Value v; - v.type = Value::VECTOR; - - for (int i=0; i<args[2].num; i++) - { - Value * r = new Value(frand(args[0].num, args[1].num)); - v.vec.push_back(r); + Value::VectorType vec; + for (int i=0; i<args[2].toDouble(); i++) { + vec.push_back(Value(frand(args[0].toDouble(), args[1].toDouble()))); } - return v; + return Value(vec); } Value builtin_min(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() >= 1 && args[0].type == Value::NUMBER) { - double val = args[0].num; + if (args.size() >= 1 && args[0].type() == Value::NUMBER) { + double val = args[0].toDouble(); for (size_t i = 1; i < args.size(); i++) - if (args[1].type == Value::NUMBER) - val = fmin(val, args[i].num); + if (args[1].type() == Value::NUMBER) + val = fmin(val, args[i].toDouble()); return Value(val); } return Value(); @@ -180,11 +176,11 @@ Value builtin_min(const Context *, const std::vector<std::string>&, const std::v Value builtin_max(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() >= 1 && args[0].type == Value::NUMBER) { - double val = args[0].num; + if (args.size() >= 1 && args[0].type() == Value::NUMBER) { + double val = args[0].toDouble(); for (size_t i = 1; i < args.size(); i++) - if (args[1].type == Value::NUMBER) - val = fmax(val, args[i].num); + if (args[1].type() == Value::NUMBER) + val = fmax(val, args[i].toDouble()); return Value(val); } return Value(); @@ -192,119 +188,117 @@ Value builtin_max(const Context *, const std::vector<std::string>&, const std::v Value builtin_sin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(sin(deg2rad(args[0].num))); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(sin(deg2rad(args[0].toDouble()))); return Value(); } Value builtin_cos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(cos(deg2rad(args[0].num))); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(cos(deg2rad(args[0].toDouble()))); return Value(); } Value builtin_asin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(rad2deg(asin(args[0].num))); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(rad2deg(asin(args[0].toDouble()))); return Value(); } Value builtin_acos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(rad2deg(acos(args[0].num))); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(rad2deg(acos(args[0].toDouble()))); return Value(); } Value builtin_tan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(tan(deg2rad(args[0].num))); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(tan(deg2rad(args[0].toDouble()))); return Value(); } Value builtin_atan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(rad2deg(atan(args[0].num))); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(rad2deg(atan(args[0].toDouble()))); return Value(); } Value builtin_atan2(const Context *, const std::vector<std::string>&, const std::vector<Value> &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))); + if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER) + return Value(rad2deg(atan2(args[0].toDouble(), args[1].toDouble()))); return Value(); } Value builtin_pow(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 2 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER) - return Value(pow(args[0].num, args[1].num)); + if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER) + return Value(pow(args[0].toDouble(), args[1].toDouble())); return Value(); } Value builtin_round(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(round(args[0].num)); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(round(args[0].toDouble())); return Value(); } Value builtin_ceil(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(ceil(args[0].num)); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(ceil(args[0].toDouble())); return Value(); } Value builtin_floor(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(floor(args[0].num)); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(floor(args[0].toDouble())); return Value(); } Value builtin_sqrt(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(sqrt(args[0].num)); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(sqrt(args[0].toDouble())); return Value(); } Value builtin_exp(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(exp(args[0].num)); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(exp(args[0].toDouble())); return Value(); } Value builtin_length(const Context *, const std::vector<std::string>&, const std::vector<Value> &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()); + 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())); } return Value(); } Value builtin_log(const Context *, const std::vector<std::string>&, const std::vector<Value> &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)); + 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)); return Value(); } Value builtin_ln(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) { - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(log(args[0].num)); + if (args.size() == 1 && args[0].type() == Value::NUMBER) + return Value(log(args[0].toDouble())); return Value(); } @@ -321,13 +315,16 @@ Value builtin_str(const Context *, const std::vector<std::string>&, const std::v Value builtin_lookup(const Context *, const std::vector<std::string>&, const std::vector<Value> &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) + 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) return Value(); - if (!args[1].vec[0]->getv2(low_p, low_v) || !args[1].vec[0]->getv2(high_p, high_v)) + if (!args[1].toVector()[0].getVec2(low_p, low_v) || !args[1].toVector()[0].getVec2(high_p, high_v)) return Value(); - for (size_t i = 1; i < args[1].vec.size(); i++) { + for (size_t i = 1; i < args[1].toVector().size(); i++) { double this_p, this_v; - if (args[1].vec[i]->getv2(this_p, this_v)) { + if (args[1].toVector()[i].getVec2(this_p, this_v)) { if (this_p <= p && (this_p > low_p || low_p > p)) { low_p = this_p; low_v = this_v; @@ -394,94 +391,90 @@ Value builtin_search(const Context *, const std::vector<std::string>&, const std const Value &findThis = args[0]; const Value &searchTable = args[1]; - unsigned int num_returns_per_match = (args.size() > 2) ? args[2].num : 1; - unsigned int index_col_num = (args.size() > 3) ? args[3].num : 0; + 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; - Value returnVector; - returnVector.type = Value::VECTOR; + Value::VectorType returnvec; - if (findThis.type == Value::NUMBER) { + if (findThis.type() == Value::NUMBER) { unsigned int matchCount = 0; - Value *resultVector = new Value(); - resultVector->type = Value::VECTOR; - for (size_t j = 0; j < searchTable.vec.size(); j++) { - if (searchTable.vec[j]->vec[index_col_num]->type == Value::NUMBER && - findThis.num == searchTable.vec[j]->vec[index_col_num]->num) { - returnVector.append(new Value(double(j))); + 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))); matchCount++; if (num_returns_per_match != 0 && matchCount >= num_returns_per_match) break; } } - } else if (findThis.type == Value::STRING) { + } else if (findThis.type() == Value::STRING) { unsigned int searchTableSize; - if (searchTable.type == Value::STRING) searchTableSize = searchTable.text.size(); - else searchTableSize = searchTable.vec.size(); - for (size_t i = 0; i < findThis.text.size(); i++) { + if (searchTable.type() == Value::STRING) searchTableSize = searchTable.toString().size(); + else searchTableSize = searchTable.toVector().size(); + for (size_t i = 0; i < findThis.toString().size(); i++) { unsigned int matchCount = 0; - Value *resultVector = new Value(); - resultVector->type = Value::VECTOR; + Value::VectorType resultvec; for (size_t j = 0; j < searchTableSize; j++) { - if ((searchTable.type == Value::VECTOR && - findThis.text[i] == searchTable.vec[j]->vec[index_col_num]->text[0]) || - (searchTable.type == Value::STRING && - findThis.text[i] == searchTable.text[j])) { - Value *resultValue = new Value(double(j)); + 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))); matchCount++; - if (num_returns_per_match==1) { - returnVector.append(resultValue); + if (num_returns_per_match == 1) { + returnvec.push_back(resultValue); break; } else { - resultVector->append(resultValue); + resultvec.push_back(resultValue); } if (num_returns_per_match > 1 && matchCount >= num_returns_per_match) break; } } - if (matchCount == 0) PRINTB(" search term not found: \"%s\"", findThis.text[i]); + if (matchCount == 0) PRINTB(" search term not found: \"%s\"", findThis.toString()[i]); if (num_returns_per_match == 0 || num_returns_per_match > 1) { - returnVector.append(resultVector); + returnvec.push_back(Value(resultvec)); } } - } else if (findThis.type == Value::VECTOR) { - for (size_t i = 0; i < findThis.vec.size(); i++) { + } else if (findThis.type() == Value::VECTOR) { + for (size_t i = 0; i < findThis.toVector().size(); i++) { unsigned int matchCount = 0; - Value *resultVector = new Value(); - resultVector->type = Value::VECTOR; - for (size_t j = 0; j < searchTable.vec.size(); j++) { - if ((findThis.vec[i]->type == Value::NUMBER && - searchTable.vec[j]->vec[index_col_num]->type == Value::NUMBER && - findThis.vec[i]->num == searchTable.vec[j]->vec[index_col_num]->num) || - (findThis.vec[i]->type == Value::STRING && - searchTable.vec[j]->vec[index_col_num]->type == Value::STRING && - findThis.vec[i]->text == searchTable.vec[j]->vec[index_col_num]->text)) { - Value *resultValue = new Value(double(j)); + 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))); matchCount++; - if (num_returns_per_match==1) { - returnVector.append(resultValue); + if (num_returns_per_match == 1) { + returnvec.push_back(resultValue); break; } else { - resultVector->append(resultValue); + resultvec.push_back(resultValue); } if (num_returns_per_match > 1 && matchCount >= num_returns_per_match) break; } } if (num_returns_per_match == 1 && matchCount == 0) { - if (findThis.vec[i]->type == Value::NUMBER) { - PRINTB(" search term not found: %s",findThis.vec[i]->num); + if (findThis.toVector()[i].type() == Value::NUMBER) { + PRINTB(" search term not found: %s",findThis.toVector()[i].toDouble()); } - else if (findThis.vec[i]->type == Value::STRING) { - PRINTB(" search term not found: \"%s\"",findThis.vec[i]->text); + else if (findThis.toVector()[i].type() == Value::STRING) { + PRINTB(" search term not found: \"%s\"",findThis.toVector()[i].toString()); } - returnVector.append(resultVector); + returnvec.push_back(Value(resultvec)); } if (num_returns_per_match == 0 || num_returns_per_match > 1) { - returnVector.append(resultVector); + returnvec.push_back(Value(resultvec)); } } } else { PRINTB(" search: none performed on input %s", findThis); return Value(); } - return returnVector; + return Value(returnvec); } #define QUOTE(x__) # x__ @@ -489,22 +482,21 @@ Value builtin_search(const Context *, const std::vector<std::string>&, const std Value builtin_version(const Context *, const std::vector<std::string>&, const std::vector<Value> &) { - Value val; - val.type = Value::VECTOR; - val.append(new Value(double(OPENSCAD_YEAR))); - val.append(new Value(double(OPENSCAD_MONTH))); + Value::VectorType val; + val.push_back(Value(double(OPENSCAD_YEAR))); + val.push_back(Value(double(OPENSCAD_MONTH))); #ifdef OPENSCAD_DAY - val.append(new Value(double(OPENSCAD_DAY))); + val.push_back(Value(double(OPENSCAD_DAY))); #endif - return val; + return Value(val); } 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; - if (!val.getv3(y, m, d)) { - if (!val.getv2(y, m)) { + if (!val.getVec3(y, m, d)) { + if (!val.getVec2(y, m)) { return Value(); } } diff --git a/src/import.cc b/src/import.cc index 597ecfb..221ee55 100644 --- a/src/import.cc +++ b/src/import.cc @@ -69,17 +69,15 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati // Map old argnames to new argnames for compatibility std::vector<std::string> inst_argnames = inst->argnames; for (size_t i=0; i<inst_argnames.size(); i++) { - if (inst_argnames[i] == "filename") - inst_argnames[i] = "file"; - if (inst_argnames[i] == "layername") - inst_argnames[i] = "layer"; + if (inst_argnames[i] == "filename") inst_argnames[i] = "file"; + if (inst_argnames[i] == "layername") inst_argnames[i] = "layer"; } Context c(ctx); c.args(argnames, argexpr, inst_argnames, inst->argvalues); Value v = c.lookup_variable("file"); - std::string filename = c.getAbsolutePath(v.text); + std::string filename = c.getAbsolutePath(v.isUndefined() ? "" : v.toString()); import_type_e actualtype = this->type; if (actualtype == TYPE_UNKNOWN) { std::string extraw = boosty::extension_str( path(filename) ); @@ -91,22 +89,22 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati ImportNode *node = new ImportNode(inst, actualtype); - node->fn = c.lookup_variable("$fn").num; - node->fs = c.lookup_variable("$fs").num; - node->fa = c.lookup_variable("$fa").num; + node->fn = c.lookup_variable("$fn").toDouble(); + node->fs = c.lookup_variable("$fs").toDouble(); + node->fa = c.lookup_variable("$fa").toDouble(); node->filename = filename; - node->layername = c.lookup_variable("layer", true).text; - node->convexity = c.lookup_variable("convexity", true).num; + Value layerval = c.lookup_variable("layer", true); + node->layername = layerval.isUndefined() ? "" : layerval.toString(); + node->convexity = c.lookup_variable("convexity", true).toDouble(); - if (node->convexity <= 0) - node->convexity = 1; + if (node->convexity <= 0) node->convexity = 1; Value origin = c.lookup_variable("origin", true); node->origin_x = node->origin_y = 0; - origin.getv2(node->origin_x, node->origin_y); + origin.getVec2(node->origin_x, node->origin_y); - node->scale = c.lookup_variable("scale", true).num; + node->scale = c.lookup_variable("scale", true).toDouble(); if (node->scale <= 0) node->scale = 1; diff --git a/src/linearextrude.cc b/src/linearextrude.cc index 4f5fd14..b193181 100644 --- a/src/linearextrude.cc +++ b/src/linearextrude.cc @@ -56,9 +56,9 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst Context c(ctx); c.args(argnames, argexpr, inst->argnames, inst->argvalues); - node->fn = c.lookup_variable("$fn").num; - node->fs = c.lookup_variable("$fs").num; - node->fa = c.lookup_variable("$fa").num; + node->fn = c.lookup_variable("$fn").toDouble(); + node->fs = c.lookup_variable("$fs").toDouble(); + node->fa = c.lookup_variable("$fa").toDouble(); Value file = c.lookup_variable("file"); Value layer = c.lookup_variable("layer", true); @@ -70,19 +70,19 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst Value twist = c.lookup_variable("twist", true); Value slices = c.lookup_variable("slices", true); - if (!file.text.empty()) { + if (!file.isUndefined()) { PRINT("DEPRECATED: Support for reading files in linear_extrude will be removed in future releases. Use a child import() instead."); - node->filename = c.getAbsolutePath(file.text); + node->filename = c.getAbsolutePath(file.toString()); } - node->layername = layer.text; - node->height = height.num; - node->convexity = (int)convexity.num; - origin.getv2(node->origin_x, node->origin_y); - node->scale = scale.num; + node->layername = layer.isUndefined() ? "" : layer.toString(); + node->height = height.toDouble(); + node->convexity = (int)convexity.toDouble(); + origin.getVec2(node->origin_x, node->origin_y); + node->scale = scale.toDouble(); - if (center.type == Value::BOOL) - node->center = center.b; + if (center.type() == Value::BOOL) + node->center = center.toBool(); if (node->height <= 0) node->height = 100; @@ -93,10 +93,10 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst if (node->scale <= 0) node->scale = 1; - if (twist.type == Value::NUMBER) { - node->twist = twist.num; - if (slices.type == Value::NUMBER) { - node->slices = (int)slices.num; + if (twist.type() == Value::NUMBER) { + node->twist = twist.toDouble(); + if (slices.type() == Value::NUMBER) { + node->slices = (int)slices.toDouble(); } else { node->slices = (int)fmax(2, fabs(get_fragments_from_r(node->height, node->fn, node->fs, node->fa) * node->twist / 360)); diff --git a/src/mainwin.cc b/src/mainwin.cc index bb0f90d..daea6e3 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -972,19 +972,17 @@ void MainWindow::updateTemporalVariables() { this->root_ctx.set_variable("$t", Value(this->e_tval->text().toDouble())); - Value vpt; - vpt.type = Value::VECTOR; - vpt.append(new Value(-this->glview->object_trans_x)); - vpt.append(new Value(-this->glview->object_trans_y)); - vpt.append(new Value(-this->glview->object_trans_z)); - this->root_ctx.set_variable("$vpt", vpt); + Value::VectorType vpt; + vpt.push_back(Value(-this->glview->object_trans_x)); + vpt.push_back(Value(-this->glview->object_trans_y)); + vpt.push_back(Value(-this->glview->object_trans_z)); + this->root_ctx.set_variable("$vpt", Value(vpt)); - Value vpr; - vpr.type = Value::VECTOR; - vpr.append(new Value(fmodf(360 - this->glview->object_rot_x + 90, 360))); - vpr.append(new Value(fmodf(360 - this->glview->object_rot_y, 360))); - vpr.append(new Value(fmodf(360 - this->glview->object_rot_z, 360))); - root_ctx.set_variable("$vpr", vpr); + Value::VectorType vpr; + vpr.push_back(Value(fmodf(360 - this->glview->object_rot_x + 90, 360))); + vpr.push_back(Value(fmodf(360 - this->glview->object_rot_y, 360))); + vpr.push_back(Value(fmodf(360 - this->glview->object_rot_z, 360))); + root_ctx.set_variable("$vpr", Value(vpr)); } bool MainWindow::fileChangedOnDisk() diff --git a/src/parser.y b/src/parser.y index 2f4379a..58ca695 100644 --- a/src/parser.y +++ b/src/parser.y @@ -295,19 +295,13 @@ single_module_instantiation: expr: TOK_TRUE { - $$ = new Expression(); - $$->type = "C"; - $$->const_value = new Value(true); + $$ = new Expression(Value(true)); } | TOK_FALSE { - $$ = new Expression(); - $$->type = "C"; - $$->const_value = new Value(false); + $$ = new Expression(Value(false)); } | TOK_UNDEF { - $$ = new Expression(); - $$->type = "C"; - $$->const_value = new Value(); + $$ = new Expression(Value::undefined); } | TOK_ID { $$ = new Expression(); @@ -323,20 +317,14 @@ expr: free($3); } | TOK_STRING { - $$ = new Expression(); - $$->type = "C"; - $$->const_value = new Value(std::string($1)); - free($1); + $$ = new Expression(Value(std::string($1))); + free($1); } | TOK_NUMBER { - $$ = new Expression(); - $$->type = "C"; - $$->const_value = new Value($1); + $$ = new Expression(Value($1)); } | '[' expr ':' expr ']' { - Expression *e_one = new Expression(); - e_one->type = "C"; - e_one->const_value = new Value(1.0); + Expression *e_one = new Expression(Value(1.0)); $$ = new Expression(); $$->type = "R"; $$->children.push_back($2); @@ -351,10 +339,7 @@ expr: $$->children.push_back($6); } | '[' optional_commas ']' { - $$ = new Expression(); - $$->type = "C"; - $$->const_value = new Value(); - $$->const_value->type = Value::VECTOR; + $$ = new Expression(Value(Value::VectorType())); } | '[' vector_expr optional_commas ']' { $$ = $2; diff --git a/src/primitives.cc b/src/primitives.cc index ce52550..e02df35 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -143,9 +143,9 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstanti Context c(ctx); c.args(argnames, argexpr, inst->argnames, inst->argvalues); - node->fn = c.lookup_variable("$fn").num; - node->fs = c.lookup_variable("$fs").num; - node->fa = c.lookup_variable("$fa").num; + node->fn = c.lookup_variable("$fn").toDouble(); + node->fs = c.lookup_variable("$fs").toDouble(); + node->fa = c.lookup_variable("$fa").toDouble(); if (node->fs < F_MINIMUM) { PRINTB("WARNING: $fs too small - clamping to %f", F_MINIMUM); @@ -160,19 +160,19 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstanti if (type == CUBE) { Value size = c.lookup_variable("size"); Value center = c.lookup_variable("center"); - size.getnum(node->x); - size.getnum(node->y); - size.getnum(node->z); - size.getv3(node->x, node->y, node->z); - if (center.type == Value::BOOL) { - node->center = center.b; + size.getDouble(node->x); + size.getDouble(node->y); + size.getDouble(node->z); + size.getVec3(node->x, node->y, node->z); + if (center.type() == Value::BOOL) { + node->center = center.toBool(); } } if (type == SPHERE) { Value r = c.lookup_variable("r"); - if (r.type == Value::NUMBER) { - node->r1 = r.num; + if (r.type() == Value::NUMBER) { + node->r1 = r.toDouble(); } } @@ -183,21 +183,21 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstanti r2 = c.lookup_variable("r2"); r = c.lookup_variable("r", true); // silence warning since r has no default value Value center = c.lookup_variable("center"); - if (h.type == Value::NUMBER) { - node->h = h.num; + if (h.type() == Value::NUMBER) { + node->h = h.toDouble(); } - if (r.type == Value::NUMBER) { - node->r1 = r.num; - node->r2 = r.num; + if (r.type() == Value::NUMBER) { + node->r1 = r.toDouble(); + node->r2 = r.toDouble(); } - if (r1.type == Value::NUMBER) { - node->r1 = r1.num; + if (r1.type() == Value::NUMBER) { + node->r1 = r1.toDouble(); } - if (r2.type == Value::NUMBER) { - node->r2 = r2.num; + if (r2.type() == Value::NUMBER) { + node->r2 = r2.toDouble(); } - if (center.type == Value::BOOL) { - node->center = center.b; + if (center.type() == Value::BOOL) { + node->center = center.toBool(); } } @@ -209,18 +209,18 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstanti if (type == SQUARE) { Value size = c.lookup_variable("size"); Value center = c.lookup_variable("center"); - size.getnum(node->x); - size.getnum(node->y); - size.getv2(node->x, node->y); - if (center.type == Value::BOOL) { - node->center = center.b; + size.getDouble(node->x); + size.getDouble(node->y); + size.getVec2(node->x, node->y); + if (center.type() == Value::BOOL) { + node->center = center.toBool(); } } if (type == CIRCLE) { Value r = c.lookup_variable("r"); - if (r.type == Value::NUMBER) { - node->r1 = r.num; + if (r.type() == Value::NUMBER) { + node->r1 = r.toDouble(); } } @@ -229,7 +229,7 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstanti node->paths = c.lookup_variable("paths"); } - node->convexity = c.lookup_variable("convexity", true).num; + node->convexity = c.lookup_variable("convexity", true).toDouble(); if (node->convexity < 1) node->convexity = 1; @@ -449,14 +449,14 @@ sphere_next_r2: if (this->type == POLYHEDRON) { p->convexity = this->convexity; - for (size_t i=0; i<this->triangles.vec.size(); i++) + for (size_t i=0; i<this->triangles.toVector().size(); i++) { p->append_poly(); - for (size_t j=0; j<this->triangles.vec[i]->vec.size(); j++) { - size_t pt = this->triangles.vec[i]->vec[j]->num; - if (pt < this->points.vec.size()) { + for (size_t j=0; j<this->triangles.toVector()[i].toVector().size(); j++) { + size_t pt = this->triangles.toVector()[i].toVector()[j].toDouble(); + if (pt < this->points.toVector().size()) { double px, py, pz; - if (this->points.vec[pt]->getv3(px, py, pz)) + if (this->points.toVector()[pt].getVec3(px, py, pz)) p->insert_vertex(px, py, pz); } } @@ -502,9 +502,9 @@ sphere_next_r2: { DxfData dd; - for (size_t i=0; i<this->points.vec.size(); i++) { + for (size_t i=0; i<this->points.toVector().size(); i++) { double x,y; - if (!this->points.vec[i]->getv2(x, y)) { + if (!this->points.toVector()[i].getVec2(x, y)) { PRINTB("ERROR: Unable to convert point at index %d to a vec2 of numbers", i); delete p; return NULL; @@ -512,10 +512,10 @@ sphere_next_r2: dd.points.push_back(Vector2d(x, y)); } - if (this->paths.vec.size() == 0) + if (this->paths.toVector().size() == 0) { dd.paths.push_back(DxfData::Path()); - for (size_t i=0; i<this->points.vec.size(); i++) { + for (size_t i=0; i<this->points.toVector().size(); i++) { assert(i < dd.points.size()); // FIXME: Not needed, but this used to be an 'if' dd.paths.back().indices.push_back(i); } @@ -526,11 +526,11 @@ sphere_next_r2: } else { - for (size_t i=0; i<this->paths.vec.size(); i++) + for (size_t i=0; i<this->paths.toVector().size(); i++) { dd.paths.push_back(DxfData::Path()); - for (size_t j=0; j<this->paths.vec[i]->vec.size(); j++) { - unsigned int idx = this->paths.vec[i]->vec[j]->num; + for (size_t j=0; j<this->paths.toVector()[i].toVector().size(); j++) { + unsigned int idx = this->paths.toVector()[i].toVector()[j].toDouble(); if (idx < dd.points.size()) { dd.paths.back().indices.push_back(idx); } diff --git a/src/projection.cc b/src/projection.cc index d3e7e94..1fcf639 100644 --- a/src/projection.cc +++ b/src/projection.cc @@ -58,10 +58,10 @@ AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstant Value convexity = c.lookup_variable("convexity", true); Value cut = c.lookup_variable("cut", true); - node->convexity = (int)convexity.num; + node->convexity = (int)convexity.toDouble(); - if (cut.type == Value::BOOL) - node->cut_mode = cut.b; + if (cut.type() == Value::BOOL) + node->cut_mode = cut.toBool(); std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); diff --git a/src/render.cc b/src/render.cc index 7b0ced5..81c3f7b 100644 --- a/src/render.cc +++ b/src/render.cc @@ -53,8 +53,8 @@ AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiati c.args(argnames, argexpr, inst->argnames, inst->argvalues); Value v = c.lookup_variable("convexity"); - if (v.type == Value::NUMBER) - node->convexity = (int)v.num; + if (v.type() == Value::NUMBER) + node->convexity = (int)v.toDouble(); std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); diff --git a/src/rotateextrude.cc b/src/rotateextrude.cc index e279cf1..10a8ef9 100644 --- a/src/rotateextrude.cc +++ b/src/rotateextrude.cc @@ -56,9 +56,9 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst Context c(ctx); c.args(argnames, argexpr, inst->argnames, inst->argvalues); - node->fn = c.lookup_variable("$fn").num; - node->fs = c.lookup_variable("$fs").num; - node->fa = c.lookup_variable("$fa").num; + node->fn = c.lookup_variable("$fn").toDouble(); + node->fs = c.lookup_variable("$fs").toDouble(); + node->fa = c.lookup_variable("$fa").toDouble(); Value file = c.lookup_variable("file"); Value layer = c.lookup_variable("layer", true); @@ -66,15 +66,15 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst Value origin = c.lookup_variable("origin", true); Value scale = c.lookup_variable("scale", true); - if (!file.text.empty()) { + if (!file.isUndefined()) { PRINT("DEPRECATED: Support for reading files in rotate_extrude will be removed in future releases. Use a child import() instead."); - node->filename = c.getAbsolutePath(file.text); + node->filename = c.getAbsolutePath(file.toString()); } - node->layername = layer.text; - node->convexity = (int)convexity.num; - origin.getv2(node->origin_x, node->origin_y); - node->scale = scale.num; + node->layername = layer.isUndefined() ? "" : layer.toString(); + node->convexity = (int)convexity.toDouble(); + origin.getVec2(node->origin_x, node->origin_y); + node->scale = scale.toDouble(); if (node->convexity <= 0) node->convexity = 1; diff --git a/src/surface.cc b/src/surface.cc index e927beb..756ad74 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -79,16 +79,17 @@ AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiat Context c(ctx); c.args(argnames, argexpr, inst->argnames, inst->argvalues); - node->filename = c.getAbsolutePath(c.lookup_variable("file").text); + Value fileval = c.lookup_variable("file"); + node->filename = c.getAbsolutePath(fileval.isUndefined() ? "" : fileval.toString()); Value center = c.lookup_variable("center", true); - if (center.type == Value::BOOL) { - node->center = center.b; + if (center.type() == Value::BOOL) { + node->center = center.toBool(); } Value convexity = c.lookup_variable("convexity", true); - if (convexity.type == Value::NUMBER) { - node->convexity = (int)convexity.num; + if (convexity.type() == Value::NUMBER) { + node->convexity = (int)convexity.toDouble(); } return node; diff --git a/src/transform.cc b/src/transform.cc index c2ac194..5b71346 100644 --- a/src/transform.cc +++ b/src/transform.cc @@ -87,29 +87,29 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti { Vector3d scalevec(1,1,1); Value v = c.lookup_variable("v"); - if (!v.getv3(scalevec[0], scalevec[1], scalevec[2], 1.0)) { + if (!v.getVec3(scalevec[0], scalevec[1], scalevec[2], 1.0)) { double num; - if (v.getnum(num)) scalevec.setConstant(num); + if (v.getDouble(num)) scalevec.setConstant(num); } node->matrix.scale(scalevec); } else if (this->type == ROTATE) { Value val_a = c.lookup_variable("a"); - if (val_a.type == Value::VECTOR) + if (val_a.type() == Value::VECTOR) { Eigen::AngleAxisd rotx, roty, rotz; double a; - if (val_a.vec.size() > 0) { - val_a.vec[0]->getnum(a); + if (val_a.toVector().size() > 0) { + val_a.toVector()[0].getDouble(a); rotx = Eigen::AngleAxisd(a*M_PI/180, Vector3d::UnitX()); } - if (val_a.vec.size() > 1) { - val_a.vec[1]->getnum(a); + if (val_a.toVector().size() > 1) { + val_a.toVector()[1].getDouble(a); roty = Eigen::AngleAxisd(a*M_PI/180, Vector3d::UnitY()); } - if (val_a.vec.size() > 2) { - val_a.vec[2]->getnum(a); + if (val_a.toVector().size() > 2) { + val_a.toVector()[2].getDouble(a); rotz = Eigen::AngleAxisd(a*M_PI/180, Vector3d::UnitZ()); } node->matrix.rotate(rotz * roty * rotx); @@ -119,10 +119,10 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti Value val_v = c.lookup_variable("v"); double a = 0; - val_a.getnum(a); + val_a.getDouble(a); Vector3d axis(0,0,1); - if (val_v.getv3(axis[0], axis[1], axis[2])) { + if (val_v.getVec3(axis[0], axis[1], axis[2])) { if (axis.squaredNorm() > 0) axis.normalize(); } @@ -136,7 +136,7 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti Value val_v = c.lookup_variable("v"); double x = 1, y = 0, z = 0; - if (val_v.getv3(x, y, z)) { + if (val_v.getVec3(x, y, z)) { if (x != 0.0 || y != 0.0 || z != 0.0) { double sn = 1.0 / sqrt(x*x + y*y + z*z); x *= sn, y *= sn, z *= sn; @@ -157,17 +157,17 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti { Value v = c.lookup_variable("v"); Vector3d translatevec(0,0,0); - v.getv3(translatevec[0], translatevec[1], translatevec[2]); + v.getVec3(translatevec[0], translatevec[1], translatevec[2]); node->matrix.translate(translatevec); } else if (this->type == MULTMATRIX) { Value v = c.lookup_variable("m"); - if (v.type == Value::VECTOR) { + if (v.type() == Value::VECTOR) { for (int i = 0; i < 16; i++) { size_t x = i / 4, y = i % 4; - if (y < v.vec.size() && v.vec[y]->type == Value::VECTOR && x < v.vec[y]->vec.size()) - v.vec[y]->vec[x]->getnum(node->matrix(y, x)); + if (y < v.toVector().size() && v.toVector()[y].type() == Value::VECTOR && x < v.toVector()[y].toVector().size()) + v.toVector()[y].toVector()[x].getDouble(node->matrix(y, x)); } } } diff --git a/src/value.cc b/src/value.cc index 93c4d5e..13b395d 100644 --- a/src/value.cc +++ b/src/value.cc @@ -25,507 +25,595 @@ */ #include "value.h" -#include "mathc99.h" #include <assert.h> #include <sstream> -#include <QDir> #include <boost/foreach.hpp> -#include "printutils.h" +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/format.hpp> -Value::Value() +#include <QtCore/QDir> + +std::ostream &operator<<(std::ostream &stream, const Filename &filename) { - reset_undef(); + stream << QuotedString(QDir::current().relativeFilePath(QString::fromStdString(filename)).toStdString()); + return stream; } -Value::~Value() +// FIXME: This could probably be done more elegantly using boost::regex +std::ostream &operator<<(std::ostream &stream, const QuotedString &s) { - for (size_t i = 0; i < this->vec.size(); i++) delete this->vec[i]; - this->vec.clear(); + stream << '"'; + BOOST_FOREACH(char c, s) { + switch (c) { + case '\t': + stream << "\\t"; + break; + case '\n': + stream << "\\n"; + break; + case '"': + case '\\': + stream << '\\'; + stream << c; + break; + default: + stream << c; + } + } + stream << '"'; + return stream; } -Value::Value(bool v) +Value Value::undefined; + +Value::Value() : value(boost::blank()) { - reset_undef(); - this->type = BOOL; - this->b = v; + // std::cout << "creating undef\n"; } -Value::Value(double v) +Value::Value(bool v) : value(v) { - reset_undef(); - this->type = NUMBER; - this->num = v; + // std::cout << "creating bool\n"; } -Value::Value(const std::string &t) +Value::Value(int v) : value(double(v)) { - reset_undef(); - this->type = STRING; - this->text = t; + // std::cout << "creating int\n"; } -Value::Value(const Value &v) +Value::Value(double v) : value(v) { - *this = v; + // std::cout << "creating double " << v << "\n"; } -Value& Value::operator = (const Value &v) +Value::Value(const std::string &v) : value(v) { - reset_undef(); - this->type = v.type; - this->b = v.b; - this->num = v.num; - for (size_t i = 0; i < v.vec.size(); i++) { - this->vec.push_back(new Value(*v.vec[i])); - } - this->range_begin = v.range_begin; - this->range_step = v.range_step; - this->range_end = v.range_end; - this->text = v.text; - return *this; + // std::cout << "creating string\n"; } -Value Value::operator ! () const -{ - if (this->type == BOOL) { - return Value(!this->b); - } - return Value(); -} - -Value Value::operator && (const Value &v) const -{ - if (this->type == BOOL && v.type == BOOL) { - return Value(this->b && v.b); - } - return Value(); -} - -Value Value::operator || (const Value &v) const -{ - if (this->type == BOOL && v.type == BOOL) { - return Value(this->b || v.b); - } - return Value(); -} - -Value Value::operator + (const Value &v) const -{ - if (this->type == VECTOR && v.type == VECTOR) { - Value r; - r.type = VECTOR; - for (size_t i = 0; i < this->vec.size() && i < v.vec.size(); i++) - r.vec.push_back(new Value(*this->vec[i] + *v.vec[i])); - return r; - } - if (this->type == NUMBER && v.type == NUMBER) { - return Value(this->num + v.num); - } - return Value(); -} - -Value Value::operator - (const Value &v) const -{ - if (this->type == VECTOR && v.type == VECTOR) { - Value r; - r.type = VECTOR; - for (size_t i = 0; i < this->vec.size() && i < v.vec.size(); i++) - r.vec.push_back(new Value(*this->vec[i] - *v.vec[i])); - return r; - } - if (this->type == NUMBER && v.type == NUMBER) { - return Value(this->num - v.num); - } - return Value(); -} - -Value Value::operator * (const Value &v) const -{ - if (this->type == VECTOR && v.type == NUMBER) { - Value r; - r.type = VECTOR; - for (size_t i = 0; i < this->vec.size(); i++) - r.vec.push_back(new Value(*this->vec[i] * v)); - return r; - } - if (this->type == NUMBER && v.type == VECTOR) { - Value r; - r.type = VECTOR; - for (size_t i = 0; i < v.vec.size(); i++) - r.vec.push_back(new Value(*this * *v.vec[i])); - return r; - } - if (this->type == NUMBER && v.type == NUMBER) { - return Value(this->num * v.num); - } - if (this->type == VECTOR && v.type == VECTOR && this->vec.size() == v.vec.size() ) { - if ( this->vec[0]->type == NUMBER && v.vec[0]->type == NUMBER ) { - // Vector dot product. - double r=0.0; - for (size_t i=0; i <this->vec.size(); i++) { - if ( this->vec[i]->type != NUMBER || v.vec[i]->type != NUMBER ) return Value(); - r = r + (this->vec[i]->num * v.vec[i]->num); - } - return Value(r); - } else if ( this->vec[0]->type == VECTOR && v.vec[0]->type == NUMBER ) { - // Matrix * Vector - Value r; - r.type = VECTOR; - for ( size_t i=0; i < this->vec.size(); i++) { - double r_e=0.0; - if ( this->vec[i]->vec.size() != v.vec.size() ) return Value(); - for ( size_t j=0; j < this->vec[i]->vec.size(); j++) { - if ( this->vec[i]->vec[j]->type != NUMBER || v.vec[i]->type != NUMBER ) return Value(); - r_e = r_e + (this->vec[i]->vec[j]->num * v.vec[j]->num); - } - r.vec.push_back(new Value(r_e)); - } - return r; - } else if (this->vec[0]->type == NUMBER && v.vec[0]->type == VECTOR ) { - // Vector * Matrix - Value r; - r.type = VECTOR; - for ( size_t i=0; i < v.vec[0]->vec.size(); i++) { - double r_e=0.0; - for ( size_t j=0; j < v.vec.size(); j++) { - if ( v.vec[j]->vec.size() != v.vec[0]->vec.size() ) return Value(); - if ( this->vec[j]->type != NUMBER || v.vec[j]->vec[i]->type != NUMBER ) return Value(); - r_e = r_e + (this->vec[j]->num * v.vec[j]->vec[i]->num); - } - r.vec.push_back(new Value(r_e)); - } - return r; - } - } - if (this->type == VECTOR && v.type == VECTOR && this->vec[0]->type == VECTOR && v.vec[0]->type == VECTOR && this->vec[0]->vec.size() == v.vec.size() ) { - // Matrix * Matrix - Value rrow; - rrow.type = VECTOR; - for ( size_t i=0; i < this->vec.size(); i++ ) { - Value * rcol=new Value(); - rcol->type = VECTOR; - for ( size_t j=0; j < this->vec.size(); j++ ) { - double r_e=0.0; - for ( size_t k=0; k < v.vec.size(); k++ ) { - r_e = r_e + (this->vec[i]->vec[k]->num * v.vec[k]->vec[j]->num); - } - // PRINTB(" r_e = %s",r_e); - rcol->vec.push_back(new Value(r_e)); - } - rrow.vec.push_back(rcol); - } - return rrow; - } - return Value(); -} - -Value Value::operator / (const Value &v) const -{ - if (this->type == VECTOR && v.type == NUMBER) { - Value r; - r.type = VECTOR; - for (size_t i = 0; i < this->vec.size(); i++) - r.vec.push_back(new Value(*this->vec[i] / v)); - return r; - } - if (this->type == NUMBER && v.type == VECTOR) { - Value r; - r.type = VECTOR; - for (size_t i = 0; i < v.vec.size(); i++) - r.vec.push_back(new Value(v / *v.vec[i])); - return r; - } - if (this->type == NUMBER && v.type == NUMBER) { - return Value(this->num / v.num); - } - return Value(); -} - -Value Value::operator % (const Value &v) const -{ - if (this->type == NUMBER && v.type == NUMBER) { - return Value(fmod(this->num, v.num)); - } - return Value(); -} - -Value Value::operator < (const Value &v) const -{ - if (this->type == NUMBER && v.type == NUMBER) { - return Value(this->num < v.num); - } - else if (this->type == STRING && v.type == STRING) { - return Value(this->text < v.text); - } - return Value(); -} - -Value Value::operator <= (const Value &v) const -{ - if (this->type == NUMBER && v.type == NUMBER) { - return Value(this->num <= v.num); - } - else if (this->type == STRING && v.type == STRING) { - return Value(this->text <= v.text); - } - return Value(); -} - -Value Value::operator == (const Value &v) const -{ - if (this->type == BOOL && v.type == BOOL) { - return Value(this->b == v.b); - } - if (this->type == NUMBER && v.type == NUMBER) { - return Value(this->num == v.num); - } - if (this->type == RANGE && v.type == RANGE) { - return Value(this->range_begin == v.range_begin && this->range_step == v.range_step && this->range_end == v.range_end); - } - if (this->type == VECTOR && v.type == VECTOR) { - if (this->vec.size() != v.vec.size()) - return Value(false); - for (size_t i=0; i<this->vec.size(); i++) - if (!(*this->vec[i] == *v.vec[i]).b) - return Value(false); - return Value(true); - } - if (this->type == STRING && v.type == STRING) { - return Value(this->text == v.text); - } - return Value(false); -} - -Value Value::operator != (const Value &v) const -{ - Value eq = *this == v; - return Value(!eq.b); -} - -Value Value::operator >= (const Value &v) const -{ - if (this->type == NUMBER && v.type == NUMBER) { - return Value(this->num >= v.num); - } - else if (this->type == STRING && v.type == STRING) { - return Value(this->text >= v.text); - } - return Value(); -} - -Value Value::operator > (const Value &v) const -{ - if (this->type == NUMBER && v.type == NUMBER) { - return Value(this->num > v.num); - } - else if (this->type == STRING && v.type == STRING) { - return Value(this->text > v.text); - } - return Value(); -} - -Value Value::inv() const -{ - if (this->type == VECTOR) { - Value r; - r.type = VECTOR; - for (size_t i = 0; i < this->vec.size(); i++) - r.vec.push_back(new Value(this->vec[i]->inv())); - return r; - } - if (this->type == NUMBER) - return Value(-this->num); - return Value(); -} - -bool Value::getnum(double &v) const -{ - if (this->type != NUMBER) - return false; - v = this->num; - return true; -} - -bool Value::getv2(double &x, double &y) const -{ - if (this->type != VECTOR || this->vec.size() != 2) - return false; - if (this->vec[0]->type != NUMBER) - return false; - if (this->vec[1]->type != NUMBER) - return false; - x = this->vec[0]->num; - y = this->vec[1]->num; - return true; -} - -bool Value::getv3(double &x, double &y, double &z, double defaultval) const -{ - if (this->type == VECTOR && this->vec.size() == 2) { - if (getv2(x, y)) { - z = defaultval; - return true; - } - return false; - } - if (this->type != VECTOR || this->vec.size() != 3) - return false; - if (this->vec[0]->type != NUMBER) - return false; - if (this->vec[1]->type != NUMBER) - return false; - if (this->vec[2]->type != NUMBER) - return false; - x = this->vec[0]->num; - y = this->vec[1]->num; - z = this->vec[2]->num; - return true; -} - -void Value::reset_undef() -{ - this->type = UNDEFINED; - this->b = false; - this->num = 0; - for (size_t i = 0; i < this->vec.size(); i++) delete this->vec[i]; - this->vec.clear(); - this->range_begin = 0; - this->range_step = 0; - this->range_end = 0; - this->text = ""; +Value::Value(const char *v) : value(std::string(v)) +{ + // std::cout << "creating string from char *\n"; } -std::string Value::toString() const +Value::Value(char v) : value(std::string(1, v)) +{ + // std::cout << "creating string from char\n"; +} + +Value::Value(const VectorType &v) : value(v) +{ + // std::cout << "creating vector\n"; +} + +Value::Value(const RangeType &v) : value(v) +{ + // std::cout << "creating range\n"; +} + +Value::Value(double begin, double step, double end) : value(RangeType(begin, step, end)) +{ + // std::cout << "creating range from numbers\n"; +} + +Value::ValueType Value::type() const +{ + return static_cast<ValueType>(this->value.which()); +} + +bool Value::isUndefined() const { - std::stringstream stream; - stream.precision(16); - - switch (this->type) { - case STRING: - stream << this->text; - break; - case VECTOR: - stream << '['; - for (size_t i = 0; i < this->vec.size(); i++) { - if (i > 0) stream << ", "; - stream << *(this->vec[i]); - } - stream << ']'; - break; - case RANGE: - stream << '[' - << this->range_begin - << " : " - << this->range_step - << " : " - << this->range_end - << ']'; - break; - case NUMBER: + return this->type() == UNDEFINED; +} + +bool Value::toBool() const +{ + switch (this->type()) { + case BOOL: + return boost::get<bool>(this->value); + break; + case NUMBER: + return boost::get<double>(this->value)!= 0; + break; + case STRING: + return boost::get<std::string>(this->value).size() > 0; + break; + case VECTOR: + return boost::get<VectorType >(this->value).size() > 0; + break; + case RANGE: + return true; + break; + default: + return false; + break; + } +} + +double Value::toDouble() const +{ + double d = 0; + getDouble(d); + return d; +} + +bool Value::getDouble(double &v) const +{ + const double *d = boost::get<double>(&this->value); + if (d) { + v = *d; + return true; + } + return false; +} + +class tostring_visitor : public boost::static_visitor<std::string> +{ +public: + template <typename T> std::string operator()(const T &op1) const { + // std::cout << "[generic tostring_visitor]\n"; + return boost::lexical_cast<std::string>(op1); + } + + std::string operator()(const double &op1) const { #ifdef OPENSCAD_TESTING - // Quick and dirty hack to work around floating point rounding differences - // across platforms for testing purposes. - { - if (this->num != this->num) { // Fix for avoiding nan vs. -nan across platforms - stream << "nan"; - break; - } - std::stringstream tmp; - tmp.precision(12); - tmp.setf(std::ios_base::fixed); - tmp << this->num; - std::string tmpstr = tmp.str(); - size_t endpos = tmpstr.find_last_not_of('0'); - if (endpos >= 0 && tmpstr[endpos] == '.') endpos--; - tmpstr = tmpstr.substr(0, endpos+1); - size_t dotpos = tmpstr.find('.'); - if (dotpos != std::string::npos) { - if (tmpstr.size() - dotpos > 12) tmpstr.erase(dotpos + 12); - } - stream << tmpstr; - } + // Quick and dirty hack to work around floating point rounding differences + // across platforms for testing purposes. + if (op1 != op1) { // Fix for avoiding nan vs. -nan across platforms + return "nan"; + } + std::stringstream tmp; + tmp.precision(12); + tmp.setf(std::ios_base::fixed); + tmp << op1; + std::string tmpstr = tmp.str(); + size_t endpos = tmpstr.find_last_not_of('0'); + if (endpos >= 0 && tmpstr[endpos] == '.') endpos--; + tmpstr = tmpstr.substr(0, endpos+1); + size_t dotpos = tmpstr.find('.'); + if (dotpos != std::string::npos) { + if (tmpstr.size() - dotpos > 12) tmpstr.erase(dotpos + 12); + } + return tmpstr; #else - stream << this->num; + return boost::lexical_cast<std::string>(op1); #endif - break; - case BOOL: - stream << (this->b ? "true" : "false"); - break; - default: - stream << "undef"; - } + } + + std::string operator()(const boost::blank &v) const { + return "undef"; + } + + std::string operator()(const bool &v) const { + return v ? "true" : "false"; + } + + std::string operator()(const Value::VectorType &v) const { + std::stringstream stream; + stream << '['; + for (size_t i = 0; i < v.size(); i++) { + if (i > 0) stream << ", "; + stream << v[i]; + } + stream << ']'; + return stream.str(); + } + + std::string operator()(const Value::RangeType &v) const { + return (boost::format("[%1% : %2% : %3%]") % v.begin % v.step % v.end).str(); + } +}; - return stream.str(); +std::string Value::toString() const +{ + return boost::apply_visitor(tostring_visitor(), this->value); } -bool Value::toBool() const +const Value::VectorType &Value::toVector() const { - switch (this->type) { - case STRING: - return this->text.size() > 0; - break; - case VECTOR: - return this->vec.size() > 0; - break; - case RANGE: - return true; - break; - case NUMBER: - return this->num != 0; - break; - case BOOL: - return this->b; - break; - default: - return false; - break; - } + static VectorType empty; + + const VectorType *v = boost::get<VectorType>(&this->value); + if (v) return *v; + else return empty; } -/*! - Append a value to this vector. - This must be of type VECTOR. -*/ -void Value::append(Value *val) +bool Value::getVec2(double &x, double &y) const +{ + if (this->type() != VECTOR) return false; + + const VectorType &v = toVector(); + + if (v.size() != 2) return false; + return (v[0].getDouble(x) && v[1].getDouble(y)); +} + +bool Value::getVec3(double &x, double &y, double &z, double defaultval) const { - assert(this->type == VECTOR); - this->vec.push_back(val); + if (this->type() != VECTOR) return false; + + const VectorType &v = toVector(); + + if (v.size() == 2) { + getVec2(x, y); + z = defaultval; + return true; + } + else { + if (v.size() != 3) return false; + } + + return (v[0].getDouble(x) && v[1].getDouble(y) && v[2].getDouble(z)); } -std::ostream &operator<<(std::ostream &stream, const Value &value) +Value::RangeType Value::toRange() const { - if (value.type == Value::STRING) stream << QuotedString(value.toString()); - else stream << value.toString(); - return stream; + const RangeType *val = boost::get<RangeType>(&this->value); + if (val) { + return *val; + } + else return RangeType(0,0,0); } -std::ostream &operator<<(std::ostream &stream, const Filename &filename) +Value &Value::operator=(const Value &v) { - stream << QuotedString(QDir::current().relativeFilePath(QString::fromStdString(filename)).toStdString()); - return stream; + if (this != &v) { + this->value = v.value; + } + return *this; } -// FIXME: This could probably be done more elegantly using boost::regex -std::ostream &operator<<(std::ostream &stream, const QuotedString &s) +Value Value::operator!() const +{ + return Value(!this->toBool()); +} + +class equals_visitor : public boost::static_visitor<bool> { - stream << '"'; - BOOST_FOREACH(char c, s) { - switch (c) { - case '\t': - stream << "\\t"; - break; - case '\n': - stream << "\\n"; - break; - case '"': - case '\\': - stream << '\\'; - stream << c; - break; - default: - stream << c; - } - } - stream << '"'; - return stream; +public: + template <typename T, typename U> bool operator()(const T &op1, const U &op2) const { + return false; + } + + template <typename T> bool operator()(const T &op1, const T &op2) const { + return op1 == op2; + } +}; + +bool Value::operator==(const Value &v) const +{ + return boost::apply_visitor(equals_visitor(), this->value, v.value); +} + +bool Value::operator!=(const Value &v) const +{ + return !(*this == v); +} + +bool Value::operator&&(const Value &v) const +{ + return this->toBool() && v.toBool(); +} + +bool Value::operator||(const Value &v) const +{ + return this->toBool() || v.toBool(); +} + +class less_visitor : public boost::static_visitor<bool> +{ +public: + template <typename T, typename U> bool operator()(const T &op1, const U &op2) const { + return false; + } + + bool operator()(const double &op1, const double &op2) const { + return op1 < op2; + } + + bool operator()(const std::string &op1, const std::string &op2) const { + return op1 < op2; + } +}; + +class greater_visitor : public boost::static_visitor<bool> +{ +public: + template <typename T, typename U> bool operator()(const T &op1, const U &op2) const { + return false; + } + + bool operator()(const double &op1, const double &op2) const { + return op1 > op2; + } + + bool operator()(const std::string &op1, const std::string &op2) const { + return op1 > op2; + } +}; + +bool Value::operator<(const Value &v) const +{ + return boost::apply_visitor(less_visitor(), this->value, v.value); +} + +bool Value::operator>=(const Value &v) const +{ + return !(*this < v); +} + +bool Value::operator>(const Value &v) const +{ + return boost::apply_visitor(greater_visitor(), this->value, v.value); +} + +bool Value::operator<=(const Value &v) const +{ + return !(*this > v); +} + +class plus_visitor : public boost::static_visitor<Value> +{ +public: + template <typename T, typename U> Value operator()(const T &op1, const U &op2) const { + return Value::undefined; + } + + Value operator()(const double &op1, const double &op2) const { + return Value(op1 + op2); + } + + Value operator()(const Value::VectorType &op1, const Value::VectorType &op2) const { + Value::VectorType sum; + for (size_t i = 0; i < op1.size() && i < op2.size(); i++) { + sum.push_back(op1[i] + op2[i]); + } + return Value(sum); + } +}; + +Value Value::operator+(const Value &v) const +{ + return boost::apply_visitor(plus_visitor(), this->value, v.value); +} + +class minus_visitor : public boost::static_visitor<Value> +{ +public: + template <typename T, typename U> Value operator()(const T &op1, const U &op2) const { + return Value::undefined; + } + + Value operator()(const double &op1, const double &op2) const { + return Value(op1 - op2); + } + + Value operator()(const Value::VectorType &op1, const Value::VectorType &op2) const { + Value::VectorType sum; + for (size_t i = 0; i < op1.size() && i < op2.size(); i++) { + sum.push_back(op1[i] - op2[i]); + } + return Value(sum); + } +}; + +Value Value::operator-(const Value &v) const +{ + return boost::apply_visitor(minus_visitor(), this->value, v.value); +} + +Value Value::operator*(const Value &v) const +{ + if (this->type() == NUMBER && v.type() == NUMBER) { + return Value(this->toDouble() * v.toDouble()); + } + else if (this->type() == VECTOR && v.type() == NUMBER) { + const VectorType &vec = this->toVector(); + VectorType tmpv; + Value result(tmpv); + VectorType &dstv = boost::get<VectorType>(result.value); + BOOST_FOREACH(const Value &vecval, vec) { + dstv.push_back(vecval * v); + } + return result; + } + else if (this->type() == NUMBER && v.type() == VECTOR) { + const VectorType &vec = v.toVector(); + VectorType tmpv; + Value result(tmpv); + VectorType &dstv = boost::get<VectorType>(result.value); + BOOST_FOREACH(const Value &vecval, vec) { + dstv.push_back(*this * vecval); + } + return result; + } + else if (this->type() == VECTOR && v.type() == VECTOR && + this->toVector().size() == v.toVector().size()) { + const VectorType &vec1 = this->toVector(); + const VectorType &vec2 = v.toVector(); + if (vec1[0].type() == NUMBER && vec2[0].type() == NUMBER) { + // Vector dot product. + double r = 0.0; + for (size_t i=0;i<vec1.size();i++) { + if (vec1[i].type() != NUMBER || vec2[i].type() != NUMBER) { + return Value::undefined; + } + r += (vec1[i].toDouble() * vec2[i].toDouble()); + } + return Value(r); + // } else if ( this->vec[0]->type() == VECTOR && v.vec[0]->type() == NUMBER ) { + // // Matrix * Vector + // Value r; + // r.type() = VECTOR; + // for ( size_t i=0; i < this->vec.size(); i++) { + // double r_e=0.0; + // if ( this->vec[i]->vec.size() != v.vec.size() ) return Value(); + // for ( size_t j=0; j < this->vec[i]->vec.size(); j++) { + // if ( this->vec[i]->vec[j]->type() != NUMBER || v.vec[i]->type() != NUMBER ) return Value(); + // r_e = r_e + (this->vec[i]->vec[j]->num * v.vec[j]->num); + // } + // r.vec.push_back(new Value(r_e)); + // } + // return r; + // } else if (this->vec[0]->type() == NUMBER && v.vec[0]->type() == VECTOR ) { + // // Vector * Matrix + // Value r; + // r.type() = VECTOR; + // for ( size_t i=0; i < v.vec[0]->vec.size(); i++) { + // double r_e=0.0; + // for ( size_t j=0; j < v.vec.size(); j++) { + // if ( v.vec[j]->vec.size() != v.vec[0]->vec.size() ) return Value(); + // if ( this->vec[j]->type() != NUMBER || v.vec[j]->vec[i]->type() != NUMBER ) return Value(); + // r_e = r_e + (this->vec[j]->num * v.vec[j]->vec[i]->num); + // } + // r.vec.push_back(new Value(r_e)); + // } + // return r; + // } + } + // if (this->type() == VECTOR && v.type() == VECTOR && this->vec[0]->type() == VECTOR && v.vec[0]->type() == VECTOR && this->vec[0]->vec.size() == v.vec.size() ) { + // // Matrix * Matrix + // Value rrow; + // rrow.type() = VECTOR; + // for ( size_t i=0; i < this->vec.size(); i++ ) { + // Value * rcol=new Value(); + // rcol->type() = VECTOR; + // for ( size_t j=0; j < this->vec.size(); j++ ) { + // double r_e=0.0; + // for ( size_t k=0; k < v.vec.size(); k++ ) { + // r_e = r_e + (this->vec[i]->vec[k]->num * v.vec[k]->vec[j]->num); + // } + // rcol->vec.push_back(new Value(r_e)); + // } + // rrow.vec.push_back(rcol); + // } + // return rrow; + } + return Value::undefined; +} + +Value Value::operator/(const Value &v) const +{ + if (this->type() == NUMBER && v.type() == NUMBER) { + return Value(this->toDouble() / v.toDouble()); + } + else if (this->type() == VECTOR && v.type() == NUMBER) { + const VectorType &vec = this->toVector(); + VectorType tmpv; + Value result(tmpv); + VectorType &dstv = boost::get<VectorType>(result.value); + BOOST_FOREACH(const Value &vecval, vec) { + dstv.push_back(vecval / v); + } + return result; + } + else if (this->type() == NUMBER && v.type() == VECTOR) { + const VectorType &vec = v.toVector(); + VectorType tmpv; + Value result(tmpv); + VectorType &dstv = boost::get<VectorType>(result.value); + BOOST_FOREACH(const Value &vecval, vec) { + dstv.push_back(*this / vecval); + } + return result; + } + return Value::undefined; +} + +Value Value::operator%(const Value &v) const +{ + if (this->type() == NUMBER && v.type() == NUMBER) { + return Value(fmod(boost::get<double>(this->value), boost::get<double>(v.value))); + } + return Value::undefined; +} + +Value Value::operator-() const +{ + if (this->type() == NUMBER) { + return Value(-this->toDouble()); + } + else if (this->type() == VECTOR) { + const VectorType &vec = this->toVector(); + VectorType tmpv; + Value result(tmpv); + VectorType &dstv = boost::get<VectorType>(result.value); + BOOST_FOREACH(const Value &vecval, vec) { + dstv.push_back(-vecval); + } + return result; + } + return Value::undefined; +} + +/*! + Append a value to this vector. + This must be of valtype VECTOR. +*/ +/* + void Value::append(Value *val) + { + assert(this->type() == VECTOR); + this->vec.push_back(val); + } +*/ + +class bracket_visitor : public boost::static_visitor<Value> +{ +public: + Value operator()(const std::string &str, const double &idx) const { + int i = int(idx); + Value v; + if (i >= 0 && i < str.size()) { + v = Value(str[int(idx)]); + // std::cout << "bracket_visitor: " << v << "\n"; + } + return v; + } + + Value operator()(const Value::VectorType &vec, const double &idx) const { + int i = int(idx); + if (i >= 0 && i < vec.size()) return vec[int(idx)]; + return Value::undefined; + } + + Value operator()(const Value::RangeType &range, const double &idx) const { + switch(int(idx)) { + case 0: return Value(range.begin); + case 1: return Value(range.step); + case 2: return Value(range.end); + } + return Value::undefined; + } + + template <typename T, typename U> Value operator()(const T &op1, const U &op2) const { + // std::cout << "generic bracket_visitor\n"; + return Value::undefined; + } +}; + +Value Value::operator[](const Value &v) +{ + return boost::apply_visitor(bracket_visitor(), this->value, v.value); } diff --git a/src/value.h b/src/value.h index 4a67fbc..8534e62 100644 --- a/src/value.h +++ b/src/value.h @@ -3,6 +3,8 @@ #include <vector> #include <string> +#include <boost/variant.hpp> +#include <boost/lexical_cast.hpp> class QuotedString : public std::string { @@ -23,68 +25,95 @@ std::ostream &operator<<(std::ostream &stream, const Filename &filename); class Value { public: - enum type_e { - UNDEFINED, - BOOL, - NUMBER, - RANGE, - VECTOR, - STRING - }; - - enum type_e type; - - bool b; - double num; - std::vector<Value*> vec; - double range_begin; - double range_step; - double range_end; - std::string text; - - Value(); - ~Value(); - - Value(bool v); - Value(double v); - Value(const std::string &t); - - Value(const Value &v); - Value& operator = (const Value &v); - - Value operator ! () const; - Value operator && (const Value &v) const; - Value operator || (const Value &v) const; - - Value operator + (const Value &v) const; - Value operator - (const Value &v) const; - Value operator * (const Value &v) const; - Value operator / (const Value &v) const; - Value operator % (const Value &v) const; - - Value operator < (const Value &v) const; - Value operator <= (const Value &v) const; - Value operator == (const Value &v) const; - Value operator != (const Value &v) const; - Value operator >= (const Value &v) const; - Value operator > (const Value &v) const; - - Value inv() const; - - bool getnum(double &v) const; - bool getv2(double &x, double &y) const; - bool getv3(double &x, double &y, double &z, double defaultval = 0.0) const; - - std::string toString() const; - - bool toBool() const; - - void append(Value *val); + struct RangeType { + RangeType(double begin, double step, double end) + : begin(begin), step(step), end(end) {} + + bool operator==(const RangeType &other) const { + return this->begin == other.begin && + this->step == other.step && + this->end == other.end; + } + + double begin; + double step; + double end; + }; + + typedef std::vector<Value> VectorType; + + enum ValueType { + UNDEFINED, + BOOL, + NUMBER, + STRING, + VECTOR, + RANGE + }; + static Value undefined; + + Value(); + Value(bool v); + Value(int v); + Value(double v); + Value(const std::string &v); + Value(const char *v); + Value(const char v); + Value(const VectorType &v); + Value(const RangeType &v); + Value(double begin, double step, double end); + ~Value() {} + + ValueType type() const; + bool isUndefined() const; + + double toDouble() const; + bool getDouble(double &v) const; + bool toBool() const; + std::string toString() const; + const VectorType &toVector() const; + bool getVec2(double &x, double &y) const; + bool getVec3(double &x, double &y, double &z, double defaultval = 0.0) const; + RangeType toRange() const; + + Value &operator=(const Value &v); + Value operator!() const; + bool operator==(const Value &v) const; + bool operator!=(const Value &v) const; + bool operator&&(const Value &v) const; + bool operator||(const Value &v) const; + bool operator<(const Value &v) const; + bool operator<=(const Value &v) const; + bool operator>=(const Value &v) const; + bool operator>(const Value &v) const; + Value operator-() const; + Value operator[](const Value &v); + Value operator+(const Value &v) const; + Value operator-(const Value &v) const; + Value operator*(const Value &v) const; + Value operator/(const Value &v) const; + Value operator%(const Value &v) const; + + /* + bool getnum(double &v) const; + bool getv2(double &x, double &y) const; + bool getv3(double &x, double &y, double &z, double defaultval = 0.0) const; + + bool toBool() const; + + void append(Value *val); + */ + + friend std::ostream &operator<<(std::ostream &stream, const Value &value) { + if (value.type() == Value::STRING) stream << QuotedString(value.toString()); + else stream << value.toString(); + return stream; + } + + typedef boost::variant< boost::blank, bool, double, std::string, VectorType, RangeType > Variant; private: - void reset_undef(); + Variant value; }; -std::ostream &operator<<(std::ostream &stream, const Value &value); - #endif |