diff --git a/src/func.cc b/src/func.cc index 878bc1c6..6001475f 100644 --- a/src/func.cc +++ b/src/func.cc @@ -36,6 +36,10 @@ #include "printutils.h" #include +#include +using boost::math::isnan; +using boost::math::isinf; + /* Random numbers @@ -598,6 +602,71 @@ Value builtin_parent_module(const Context *, const EvalContext *evalctx) return Value(Module::stack_element(s - 1 - n)); } +Value builtin_norm(const Context *, const EvalContext *evalctx) +{ + if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::VECTOR) { + double sum = 0; + Value::VectorType v = evalctx->getArgValue(0).toVector(); + for (size_t i = 0; i < v.size(); i++) + if (v[i].type() == Value::NUMBER) + sum += pow(v[i].toDouble(),2); + else { + PRINT(" WARNING: Incorrect arguments to norm()"); + return Value(); + } + return Value(sqrt(sum)); + } + return Value(); +} + +Value builtin_cross(const Context *, const EvalContext *evalctx) +{ + if (evalctx->numArgs() != 2) { + PRINT("WARNING: Invalid number of parameters for cross()"); + return Value(); + } + + Value arg0 = evalctx->getArgValue(0); + Value arg1 = evalctx->getArgValue(1); + if ((arg0.type() != Value::VECTOR) || (arg1.type() != Value::VECTOR)) { + PRINT("WARNING: Invalid type of parameters for cross()"); + return Value(); + } + + Value::VectorType v0 = arg0.toVector(); + Value::VectorType v1 = arg1.toVector(); + if ((v0.size() != 3) || (v1.size() != 3)) { + PRINT("WARNING: Invalid vector size of parameter for cross()"); + return Value(); + } + for (unsigned int a = 0;a < 3;a++) { + if ((v0[a].type() != Value::NUMBER) || (v1[a].type() != Value::NUMBER)) { + PRINT("WARNING: Invalid value in parameter vector for cross()"); + return Value(); + } + double d0 = v0[a].toDouble(); + double d1 = v1[a].toDouble(); + if (isnan(d0) || isnan(d1)) { + PRINT("WARNING: Invalid value (NaN) in parameter vector for cross()"); + return Value(); + } + if (isinf(d0) || isinf(d1)) { + PRINT("WARNING: Invalid value (INF) in parameter vector for cross()"); + return Value(); + } + } + + double x = v0[1].toDouble() * v1[2].toDouble() - v0[2].toDouble() * v1[1].toDouble(); + double y = v0[2].toDouble() * v1[0].toDouble() - v0[0].toDouble() * v1[2].toDouble(); + double z = v0[0].toDouble() * v1[1].toDouble() - v0[1].toDouble() * v1[0].toDouble(); + + Value::VectorType result; + result.push_back(Value(x)); + result.push_back(Value(y)); + result.push_back(Value(z)); + return Value(result); +} + void register_builtin_functions() { Builtins::init("abs", new BuiltinFunction(&builtin_abs)); @@ -627,5 +696,7 @@ void register_builtin_functions() Builtins::init("search", new BuiltinFunction(&builtin_search)); Builtins::init("version", new BuiltinFunction(&builtin_version)); Builtins::init("version_num", new BuiltinFunction(&builtin_version_num)); + Builtins::init("norm", new BuiltinFunction(&builtin_norm)); + Builtins::init("cross", new BuiltinFunction(&builtin_cross)); Builtins::init("parent_module", new BuiltinFunction(&builtin_parent_module)); } diff --git a/testdata/scad/functions/cross-tests.scad b/testdata/scad/functions/cross-tests.scad new file mode 100644 index 00000000..5dda5a01 --- /dev/null +++ b/testdata/scad/functions/cross-tests.scad @@ -0,0 +1,17 @@ +echo(cross([2, 3, 4], [5, 6, 7])); +echo(cross([2, 1, -3], [0, 4, 5])); +echo(cross([2, 1, -3], cross([2, 3, 4], [5, 6, 7]))); + +echo(cross([2, 0/0, -3], [0, 4, 5])); +echo(cross([2, 1/0, -3], [0, 4, 5])); +echo(cross([2, -1/0, -3], [0, 4, 5])); + +echo(cross(0)); +echo(cross(0, 1)); +echo(cross(0, "a")); +echo(cross(0, 1, 3)); +echo(cross([0], [1])); +echo(cross([1, 2, 3], [1, 2])); +echo(cross([1, 2, 3], [1, 2, "a"])); +echo(cross([1, 2, 3], [1, 2, [0]])); +echo(cross([1, 2, 3], [1, 2, [1:2]])); diff --git a/testdata/scad/functions/norm-tests.scad b/testdata/scad/functions/norm-tests.scad new file mode 100644 index 00000000..dfa54418 --- /dev/null +++ b/testdata/scad/functions/norm-tests.scad @@ -0,0 +1,27 @@ +u=undef; + +echo(norm([])); +echo(norm([1])); +echo(norm([1,2])); +echo(norm([1,2,3])); +echo(norm([1,2,3,4])); +echo(norm()); + +echo(norm([1,2,0/0])); +echo(norm([1,2,1/0])); +echo(norm([1,2,-1/0])); + +echo(norm("")); +echo(norm("abcd")); +echo(norm(true)); +echo(norm([1:4])); + +echo(norm([1, 2, "a"])); +echo(norm([1, 2, []])); +echo(norm([1, 2, [1]])); +echo(norm([1, 2, [1:3]])); +echo(norm([[1,2,3,4],[1,2,3],[1,2],[1]])); + +echo(norm(u)); +echo(norm(u, u)); +echo(norm(a, a)); diff --git a/tests/regression/echotest/cross-tests-expected.echo b/tests/regression/echotest/cross-tests-expected.echo new file mode 100644 index 00000000..ad80dacf --- /dev/null +++ b/tests/regression/echotest/cross-tests-expected.echo @@ -0,0 +1,27 @@ +ECHO: [-3, 6, -3] +ECHO: [17, -10, 8] +ECHO: [15, 15, 15] +WARNING: Invalid value (NaN) in parameter vector for cross() +ECHO: undef +WARNING: Invalid value (INF) in parameter vector for cross() +ECHO: undef +WARNING: Invalid value (INF) in parameter vector for cross() +ECHO: undef +WARNING: Invalid number of parameters for cross() +ECHO: undef +WARNING: Invalid type of parameters for cross() +ECHO: undef +WARNING: Invalid type of parameters for cross() +ECHO: undef +WARNING: Invalid number of parameters for cross() +ECHO: undef +WARNING: Invalid vector size of parameter for cross() +ECHO: undef +WARNING: Invalid vector size of parameter for cross() +ECHO: undef +WARNING: Invalid value in parameter vector for cross() +ECHO: undef +WARNING: Invalid value in parameter vector for cross() +ECHO: undef +WARNING: Invalid value in parameter vector for cross() +ECHO: undef diff --git a/tests/regression/echotest/norm-tests-expected.echo b/tests/regression/echotest/norm-tests-expected.echo new file mode 100644 index 00000000..cfa2e572 --- /dev/null +++ b/tests/regression/echotest/norm-tests-expected.echo @@ -0,0 +1,26 @@ +ECHO: 0 +ECHO: 1 +ECHO: 2.2360679775 +ECHO: 3.74165738677 +ECHO: 5.47722557505 +ECHO: undef +ECHO: nan +ECHO: inf +ECHO: inf +ECHO: undef +ECHO: undef +ECHO: undef +ECHO: undef + WARNING: Incorrect arguments to norm() +ECHO: undef + WARNING: Incorrect arguments to norm() +ECHO: undef + WARNING: Incorrect arguments to norm() +ECHO: undef + WARNING: Incorrect arguments to norm() +ECHO: undef + WARNING: Incorrect arguments to norm() +ECHO: undef +ECHO: undef +ECHO: undef +ECHO: undef