diff options
| -rw-r--r-- | src/CGALEvaluator.cc | 2 | ||||
| -rw-r--r-- | src/ModuleCache.cc | 2 | ||||
| -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 | 24 | ||||
| -rw-r--r-- | src/openscad.cc | 2 | ||||
| -rw-r--r-- | src/openscad.h | 3 | ||||
| -rw-r--r-- | src/parser.y | 31 | ||||
| -rw-r--r-- | src/parsersettings.cc | 5 | ||||
| -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 | 1004 | ||||
| -rw-r--r-- | src/value.h | 153 | ||||
| -rw-r--r-- | testdata/scad/bugs/issue95-normalization-crash.scad | 135 | ||||
| -rw-r--r-- | testdata/scad/misc/vector-values.scad | 6 | ||||
| -rw-r--r-- | tests/CSGTextRenderer.cc | 1 | ||||
| -rw-r--r-- | tests/cgalstlsanitytest.cc | 24 | ||||
| -rw-r--r-- | tests/regression/echotest/vector-values-expected.txt | 4 | ||||
| -rw-r--r-- | tests/tests-common.cc | 26 | 
31 files changed, 1015 insertions, 1035 deletions
| diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index 46f4cfa..a570df4 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -81,7 +81,7 @@ void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedr  			break;  		}  	} -	catch (CGAL::Assertion_exception e) { +	catch (CGAL::Failure_exception e) {  		// union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad  		std::string opstr = op == CGE_UNION ? "union" : op == CGE_INTERSECTION ? "intersection" : op == CGE_DIFFERENCE ? "difference" : op == CGE_MINKOWSKI ? "minkowski" : "UNKNOWN";  		PRINTB("CGAL error in CGAL_Nef_polyhedron's %s operator: %s", opstr % e.what()); diff --git a/src/ModuleCache.cc b/src/ModuleCache.cc index 70b1fb9..d03d121 100644 --- a/src/ModuleCache.cc +++ b/src/ModuleCache.cc @@ -83,7 +83,7 @@ Module *ModuleCache::evaluate(const std::string &filename)  		this->entries[filename] = e;  		std::string pathname = boosty::stringy(fs::path(filename).parent_path()); -		lib_mod = dynamic_cast<Module*>(parse(text.c_str(), pathname.c_str(), 0)); +		lib_mod = dynamic_cast<Module*>(parse(text.c_str(), pathname.c_str(), false));  		if (lib_mod) {  			this->entries[filename].module = lib_mod; 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 087cb30..ecbe271 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -99,6 +99,8 @@  #define OPENCSG_VERSION_STRING "unknown, <1.3.2"  #endif +extern QString examplesdir; +  // Global application state  unsigned int GuiLocker::gui_locked = 0; @@ -976,19 +978,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/openscad.cc b/src/openscad.cc index 7fe054f..798bdec 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -205,7 +205,7 @@ int main(int argc, char **argv)  	}  #endif -	currentdir = boosty::stringy( fs::current_path() ); +	currentdir = boosty::stringy(fs::current_path());  	QDir exdir(QApplication::instance()->applicationDirPath());  #ifdef Q_WS_MAC diff --git a/src/openscad.h b/src/openscad.h index 8b49ba2..8d9a01e 100644 --- a/src/openscad.h +++ b/src/openscad.h @@ -33,12 +33,9 @@ extern int get_fragments_from_r(double r, double fn, double fs, double fa);  #include <string>  extern std::string commandline_commands; -#include <QString>  // The CWD when application started. We shouldn't change CWD, but until we stop  // doing this, use currentdir to get the original CWD.  extern std::string currentdir; -extern QString examplesdir; -  #endif diff --git a/src/parser.y b/src/parser.y index 195e7a8..b36c41b 100644 --- a/src/parser.y +++ b/src/parser.y @@ -294,19 +294,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(); @@ -322,20 +316,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); @@ -350,10 +338,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/parsersettings.cc b/src/parsersettings.cc index a3a02b7..134514c 100644 --- a/src/parsersettings.cc +++ b/src/parsersettings.cc @@ -1,6 +1,5 @@  #include "parsersettings.h"  #include <boost/filesystem.hpp> -#include <qglobal.h> // Needed for Q_ defines - move the offending code somewhere else  using namespace boost::filesystem;  #include "boosty.h" @@ -22,10 +21,10 @@ void parser_init(const std::string &applicationpath)  	std::string librarydir;  	path libdir(applicationpath);  	path tmpdir; -#ifdef Q_WS_MAC +#ifdef __APPLE__  	libdir /= "../Resources"; // Libraries can be bundled  	if (!is_directory(libdir / "libraries")) libdir /= "../../.."; -#elif defined(Q_OS_UNIX) +#elif !defined(WIN32)  	if (is_directory(tmpdir = libdir / "../share/openscad/libraries")) {  		librarydir = boosty::stringy( tmpdir );  	} else if (is_directory(tmpdir = libdir / "../../share/openscad/libraries")) { 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..2602f32 100644 --- a/src/value.cc +++ b/src/value.cc @@ -25,507 +25,599 @@   */  #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) +{ +  stream << QuotedString(QDir::current().relativeFilePath(QString::fromStdString(filename)).toStdString()); +  return stream; +} + +// FIXME: This could probably be done more elegantly using boost::regex +std::ostream &operator<<(std::ostream &stream, const QuotedString &s)  { -	reset_undef(); +  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() +Value Value::undefined; + +Value::Value() : value(boost::blank())  { -	for (size_t i = 0; i < this->vec.size(); i++) delete this->vec[i]; -	this->vec.clear(); +  //  std::cout << "creating undef\n";  } -Value::Value(bool v) +Value::Value(bool v) : value(v)  { -	reset_undef(); -	this->type = BOOL; -	this->b = v; +  //  std::cout << "creating bool\n";  } -Value::Value(double v) +Value::Value(int v) : value(double(v))  { -	reset_undef(); -	this->type = NUMBER; -	this->num = v; +  //  std::cout << "creating int\n";  } -Value::Value(const std::string &t) +Value::Value(double v) : value(v)  { -	reset_undef(); -	this->type = STRING; -	this->text = t; +  //  std::cout << "creating double " << v << "\n";  } -Value::Value(const Value &v) +Value::Value(const std::string &v) : value(v)  { -	*this = v; +  //  std::cout << "creating string\n";  } -Value& Value::operator = (const Value &v) +Value::Value(const char *v) : value(std::string(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 from char *\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(char v) : value(std::string(1, v)) +{ +  //  std::cout << "creating string from char\n";  } -std::string Value::toString() const +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 +{ +  return this->type() == UNDEFINED; +} + +bool Value::toBool() 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: +  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 &) 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  { -	assert(this->type == VECTOR); -	this->vec.push_back(val); +  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));  } -std::ostream &operator<<(std::ostream &stream, const Value &value) +bool Value::getVec3(double &x, double &y, double &z, double defaultval) const  { -	if (value.type == Value::STRING) stream << QuotedString(value.toString()); -	else stream << value.toString(); -	return stream; +  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 Filename &filename) +Value::RangeType Value::toRange() const  { -	stream << QuotedString(QDir::current().relativeFilePath(QString::fromStdString(filename)).toStdString()); -	return stream; +  const RangeType *val = boost::get<RangeType>(&this->value); +  if (val) { +    return *val; +  } +  else return RangeType(0,0,0);  } -// FIXME: This could probably be done more elegantly using boost::regex -std::ostream &operator<<(std::ostream &stream, const QuotedString &s) +Value &Value::operator=(const Value &v) +{ +  if (this != &v) { +    this->value = v.value; +  } +  return *this; +} + +Value Value::operator!() const +{ +  return Value(!this->toBool()); +} + +class equals_visitor : public boost::static_visitor<bool> +{ +public: +  template <typename T, typename U> bool operator()(const T &, const U &) 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  { -	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; +  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 &, const U &) 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 &, const U &) 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 &, const U &) 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 &, const U &) 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::multvecnum(const Value &vecval, const Value &numval) +{ +  // Vector * Number +  VectorType dstv; +  BOOST_FOREACH(const Value &val, vecval.toVector()) { +    dstv.push_back(val * numval); +  } +  return Value(dstv); +} + +Value Value::multmatvec(const Value &matrixval, const Value &vectorval) +{ +  const VectorType &matrixvec = matrixval.toVector(); +  const VectorType &vectorvec = vectorval.toVector(); + +  // Matrix * Vector +  VectorType dstv; +  for (size_t i=0;i<matrixvec.size();i++) { +    if (matrixvec[i].type() != VECTOR ||  +        matrixvec[i].toVector().size() != vectorvec.size()) { +      return Value(); +    } +    double r_e = 0.0; +    for (size_t j=0;j<matrixvec[i].toVector().size();j++) { +      if (matrixvec[i].toVector()[j].type() != NUMBER || vectorvec[j].type() != NUMBER) { +        return Value(); +      } +      r_e += matrixvec[i].toVector()[j].toDouble() * vectorvec[j].toDouble(); +    } +    dstv.push_back(Value(r_e)); +  } +  return Value(dstv); +} + +Value Value::multvecmat(const Value &vectorval, const Value &matrixval) +{ +  const VectorType &vectorvec = vectorval.toVector(); +  const VectorType &matrixvec = matrixval.toVector(); +  assert(vectorvec.size() == matrixvec.size()); +  // Vector * Matrix +  VectorType dstv; +  for (size_t i=0;i<matrixvec[0].toVector().size();i++) { +    double r_e = 0.0; +    for (size_t j=0;j<vectorvec.size();j++) { +      if (matrixvec[j].type() != VECTOR || +          matrixvec[j].toVector()[i].type() != NUMBER ||  +          vectorvec[j].type() != NUMBER) { +        return Value::undefined; +      } +      r_e += vectorvec[j].toDouble() * matrixvec[j].toVector()[i].toDouble(); +    } +    dstv.push_back(Value(r_e)); +  } +  return Value(dstv); +} + +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) { +    return multvecnum(*this, v); +  } +  else if (this->type() == NUMBER && v.type() == VECTOR) { +    return multvecnum(v, *this); +  } +  else if (this->type() == VECTOR && v.type() == VECTOR) { +    const VectorType &vec1 = this->toVector(); +    const VectorType &vec2 = v.toVector(); +    if (vec1[0].type() == NUMBER && vec2[0].type() == NUMBER && +        vec1.size() == vec2.size()) {  +        // 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 (vec1[0].type() == VECTOR && vec2[0].type() == NUMBER && +               vec1[0].toVector().size() == vec2.size()) { +      return multmatvec(vec1, vec2); +    } else if (vec1[0].type() == NUMBER && vec2[0].type() == VECTOR && +               vec1.size() == vec2.size()) { +      return multvecmat(vec1, vec2); +    } else if (vec1[0].type() == VECTOR && vec2[0].type() == VECTOR && +               vec1[0].toVector().size() == vec2.size()) { +      // Matrix * Matrix +      VectorType dstv; +      BOOST_FOREACH(const Value &srcrow, vec1) { +        dstv.push_back(multvecmat(srcrow, vec2)); +      } +      return Value(dstv); +    } +  } +  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 dstv; +    BOOST_FOREACH(const Value &vecval, vec) { +      dstv.push_back(vecval / v); +    } +    return Value(dstv); +  } +  else if (this->type() == NUMBER && v.type() == VECTOR) { +    const VectorType &vec = v.toVector(); +    VectorType dstv; +    BOOST_FOREACH(const Value &vecval, vec) { +      dstv.push_back(*this / vecval); +    } +    return Value(dstv); +  } +  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 dstv; +    BOOST_FOREACH(const Value &vecval, vec) { +      dstv.push_back(-vecval); +    } +    return Value(dstv); +  } +  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 &, const U &) 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..24fbf49 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,99 @@ 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(); -}; +  static Value multvecnum(const Value &vecval, const Value &numval); +  static Value multmatvec(const Value &matrixval, const Value &vectorval); +  static Value multvecmat(const Value &vectorval, const Value &matrixval); -std::ostream &operator<<(std::ostream &stream, const Value &value); +  Variant value; +};  #endif diff --git a/testdata/scad/bugs/issue95-normalization-crash.scad b/testdata/scad/bugs/issue95-normalization-crash.scad index 10a3f66..7bca8ed 100644 --- a/testdata/scad/bugs/issue95-normalization-crash.scad +++ b/testdata/scad/bugs/issue95-normalization-crash.scad @@ -1,128 +1,19 @@  //  // Reported by Triffid Hunter. -// Causes a crash in CCGTermNormalizer::normalizePass() +// Causes a crash in CSGTermNormalizer::normalizePass()  // -pi = 3.141592653589; -sl = 0.5; +difference() { +  union() { +    translate([0, -20, 0]) cube([30, 2, 40]); +    cube(); +  } -w = 400; - -pulley_diam = 28; -bearing_diam = 22; //include size of bearing guides - -module crx(size=[1, 1, 1]) { -	linear_extrude(height=size[2]) -	square([size[0], size[1]], center=true); +  translate([15.5, -19, 14]) { +    cylinder(r=5, h=2); +    rotate([-90, 0, 0]) difference() { +      translate([0, 0, 2]) cylinder(r=2, h=3); +      translate([0, 0, 4]) cylinder(h=2); +    } +  }  } - -module cyl(r=1, h=1, center=false) { -	cylinder(r=r, h=h, center=center, $fn=r * 2 * pi / sl); -} - -module lm8uu() { -	cyl(r=15 /2, h=24); -} - -module nema17() { -	translate([0, 0, -48]) crx([42, 42, 48]); -	translate([0, 0, -1]) { -		cyl(r=2.5, h=26); -		cyl(r=22.5 / 2, h=3.1); -	} -	translate([0, 0, 2.1]) { -		difference() { -			cyl(r=pulley_diam / 2, h=11.5); -			translate([0, 0, (11.5 - 8) / 2]) rotate_extrude() -				translate([21.5 / 2, 0]) -					square(8); -		} -	} -	cyl(r=17.5 / 2, h=19.5); -	for (i=[0:3]) { -		rotate([0, 0, i * 90]) -		translate([31 / 2, 31 / 2, -1]) { -			cyl(r=1.5, h=11); -			translate([0, 0, 5.5]) -				cyl(r=4, h=30); -		} -	} -} - -module bearing608() { -	cyl(r=bearing_diam / 2, h = 7); -} - -module rods() { -	for (i=[0:1]) { -		translate([25, 0, i * 70]) -			rotate([0, -90, 0]) -				cyl(r=4, h=420); -	} -	 -	translate([0, 10, -40]) { -		cyl(r=3, h=150); -		translate([0, 0, 34]) cylinder(r=10 / cos(180 / 6) / 2, h=6, $fn=6); -	} -	 -	translate([30, 10, -40]) { -		cyl(r=4, h=150); -	} -} - -module lm8uu_holder() { -	render() -	difference() { -		union() { -			translate([0, 0, -13]) difference() { -				hull() { -					translate([-9, -9, -1]) cube([18, 1, 28]); -					translate([0, 1, -1]) cyl(r=18 / 2, h = 28); -				} -				translate([-10, 5, -1]) cube([20, 10, 28]); -				translate([-10, -3, 11 - 5]) cube([20, 20, 4]); -				translate([-10, -3, 11 + 5]) cube([20, 20, 4]); -			} -		} -		translate([0, 0, -11]) { -			hull() { -				#lm8uu(); -				translate([0, 10, 0]) cyl(r=6, h=24); -			} -			translate([0, 0, -3]) hull() { -				cyl(r=5, h=30); -				translate([0, 10, 0]) cyl(r=5, h=30); -			} -		} -	} -} - -module x_end_motor() { -	difference() { -		union() { -			translate([-10, -18, -19]) #cube([50, 2, 90]); -			translate([30, 10, 60]) lm8uu_holder(); -			translate([30, 10, -5]) lm8uu_holder(); -		} -		#rods(); -		 -		translate([15.5, -19, 14]) { -			rotate([90, 0, 0]) cyl(r=30 / 2, h= 50, center=true); -			rotate([-90, 45, 0]) -				#nema17(); -			translate([-w, 4, 0]) -				rotate([-90, 0, 0]) -					bearing608(); -			translate([0, 5, 0]) hull() { -				#translate([0, 0, 24 / 2 - 1.5]) cube([1, 5, 1.5]); -				#translate([-w, 0, bearing_diam / 2 ]) cube([1, 5, 1.5]); -			} -			translate([0, 5, 0]) hull() { -				#translate([0, 0, 24 / -2]) cube([1, 5, 1.5]); -				#translate([-w, 0, bearing_diam / -2 - 1.5]) cube([1, 5, 1.5]); -			} -		} -	} -} - -x_end_motor();
\ No newline at end of file diff --git a/testdata/scad/misc/vector-values.scad b/testdata/scad/misc/vector-values.scad index 1872b39..59c2ee5 100644 --- a/testdata/scad/misc/vector-values.scad +++ b/testdata/scad/misc/vector-values.scad @@ -8,7 +8,7 @@ echo(str("Testing vector dot product: ",c1));  d1=[1,0];  echo(str("  Bounds check: ",a1*d1)); -m2=[[0,1],[1,0]]; +m2=[[0,1],[1,0],[2,3]];  v2=[2,3];  p2=m2*v2;  echo(str("Testing matrix * vector: ",p2)); @@ -16,8 +16,8 @@ echo(str("Testing matrix * vector: ",p2));  d2=[0,0,1];  echo(str("  Bounds check: ",m2*d2)); -m3=[[1,-1,1],[1,0,-1]]; -v3=[1,1]; +m3=[[1,-1],[1,0],[2,3]]; +v3=[1,2,3];  p3=v3*m3;  echo(str("Testing vector * matrix: ",p3)); diff --git a/tests/CSGTextRenderer.cc b/tests/CSGTextRenderer.cc index b55c88f..d254820 100644 --- a/tests/CSGTextRenderer.cc +++ b/tests/CSGTextRenderer.cc @@ -13,7 +13,6 @@  #include <sstream>  #include <iostream>  #include <assert.h> -#include <QRegExp>  bool CSGTextRenderer::isCached(const AbstractNode &node)  { diff --git a/tests/cgalstlsanitytest.cc b/tests/cgalstlsanitytest.cc index d0d0077..7241482 100644 --- a/tests/cgalstlsanitytest.cc +++ b/tests/cgalstlsanitytest.cc @@ -132,17 +132,27 @@ int main(int argc, char **argv)  	if (!N.empty()) {  		std::ofstream outfile;  		outfile.open(outfilename); - -		std::stringstream out; -		export_stl(&N, out); -		if (out.str().find("nan") != string::npos) { -			outfile << "Error: nan found\n"; +			 +		if (N.dim != 3) { +			outfile << "Error: Current top level object is not a 3D object.\n";  			retval = 2;  		} -		if (out.str().find("inf") != string::npos) { -			outfile << "Error: inf found\n"; +		else if (!N.p3->is_simple()) { +			outfile << "Error: Object isn't a valid 2-manifold! Modify your design.\n";  			retval = 2;  		} +		else { +			std::stringstream out; +			export_stl(&N, out); +			if (out.str().find("nan") != string::npos) { +				outfile << "Error: nan found\n"; +				retval = 2; +			} +			if (out.str().find("inf") != string::npos) { +				outfile << "Error: inf found\n"; +				retval = 2; +			} +		}  		outfile.close();  	} diff --git a/tests/regression/echotest/vector-values-expected.txt b/tests/regression/echotest/vector-values-expected.txt index 7654892..78053b9 100644 --- a/tests/regression/echotest/vector-values-expected.txt +++ b/tests/regression/echotest/vector-values-expected.txt @@ -1,8 +1,8 @@  ECHO: "Testing vector dot product: 14"  ECHO: "  Bounds check: undef" -ECHO: "Testing matrix * vector: [3, 2]" +ECHO: "Testing matrix * vector: [3, 2, 13]"  ECHO: "  Bounds check: undef" -ECHO: "Testing vector * matrix: [2, -1, 0]" +ECHO: "Testing vector * matrix: [9, 8]"  ECHO: "  Bounds check: undef"  ECHO: "Testing id matrix * id matrix: [[1, 0], [0, 1]]"  ECHO: "Testing asymmetric matrix * matrix: [[2, 1], [-1, 0]]" diff --git a/tests/tests-common.cc b/tests/tests-common.cc index 5b0cc3b..703e1c5 100644 --- a/tests/tests-common.cc +++ b/tests/tests-common.cc @@ -2,31 +2,25 @@  #include "openscad.h"  #include "module.h"  #include "handle_dep.h" +#include "boosty.h" -#include <QFile> -#include <QFileInfo>  #include <sstream> +#include <fstream>  Module *parsefile(const char *filename)  {  	Module *root_module = NULL; -	QFileInfo fileInfo(filename);  	handle_dep(filename); -	FILE *fp = fopen(filename, "rt"); -	if (!fp) { +	std::ifstream ifs(filename); +	if (!ifs.is_open()) {  		fprintf(stderr, "Can't open input file `%s'!\n", filename); -	} else { -		std::stringstream text; -		char buffer[513]; -		int ret; -		while ((ret = fread(buffer, 1, 512, fp)) > 0) { -			buffer[ret] = 0; -			text << buffer; -		} -		fclose(fp); -		text << "\n" << commandline_commands; -		root_module = parse(text.str().c_str(), fileInfo.absolutePath().toLocal8Bit(), false); +	} +	else { +		std::string text((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>()); +		text += "\n" + commandline_commands; +		std::string pathname = boosty::stringy(fs::path(filename).parent_path()); +		root_module = parse(text.c_str(), pathname.c_str(), false);  		if (root_module) {  			root_module->handleDependencies();  		} | 
