2009-06-20 23:00:19 +04:00
/*
2011-01-21 04:21:09 +03:00
* OpenSCAD ( www . openscad . org )
* Copyright ( C ) 2009 - 2011 Clifford Wolf < clifford @ clifford . at > and
* Marius Kintel < marius @ kintel . net >
2009-06-20 23:00:19 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
2010-02-01 12:34:18 +03:00
* As a special exception , you have permission to link this program
* with the CGAL library and distribute executables , as long as you
* follow the requirements of the GNU GPL in regard to all of the
* software in the executable aside from CGAL .
*
2009-06-20 23:00:19 +04:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
2015-03-22 16:17:12 +03:00
# include "mathc99.h"
2010-01-30 07:26:05 +03:00
# include "function.h"
# include "expression.h"
2013-04-09 08:28:16 +04:00
# include "evalcontext.h"
2010-01-30 07:26:05 +03:00
# include "builtin.h"
2010-11-08 00:29:34 +03:00
# include <sstream>
2011-08-13 03:48:59 +04:00
# include <ctime>
2014-04-25 10:46:45 +04:00
# include <limits>
2011-09-03 08:10:36 +04:00
# include <algorithm>
# include "stl-utils.h"
2012-02-15 08:04:40 +04:00
# include "printutils.h"
2014-11-25 01:37:42 +03:00
# include "stackcheck.h"
2014-12-12 00:09:55 +03:00
# include "exceptions.h"
2013-04-19 02:34:14 +04:00
# include <boost/foreach.hpp>
2013-01-06 21:06:55 +04:00
2014-02-17 02:04:48 +04:00
# include <boost/math/special_functions/fpclassify.hpp>
using boost : : math : : isnan ;
using boost : : math : : isinf ;
2013-01-06 21:06:55 +04:00
/*
Random numbers
Newer versions of boost / C + + include a non - deterministic random_device and
auto / bind ( ) s for random function objects , but we are supporting older systems .
*/
2013-01-06 09:27:42 +04:00
# include <boost/random/mersenne_twister.hpp>
2013-01-30 07:59:59 +04:00
# include <boost/random/uniform_real.hpp>
2013-12-05 10:56:54 +04:00
/*Unicode support for string lengths and array accesses*/
# include <glib.h>
2013-01-06 09:27:42 +04:00
2013-01-06 20:35:31 +04:00
# ifdef __WIN32__
# include <process.h>
int process_id = _getpid ( ) ;
# else
# include <sys/types.h>
# include <unistd.h>
int process_id = getpid ( ) ;
# endif
2013-01-30 07:59:59 +04:00
boost : : mt19937 deterministic_rng ;
boost : : mt19937 lessdeterministic_rng ( std : : time ( 0 ) + process_id ) ;
2009-06-20 23:00:19 +04:00
AbstractFunction : : ~ AbstractFunction ( )
{
}
2014-11-23 08:59:17 +03:00
// FIXME: Is this needed?
ValuePtr AbstractFunction : : evaluate ( const Context * , const EvalContext * evalctx ) const
2009-06-20 23:00:19 +04:00
{
2013-05-20 08:31:18 +04:00
( void ) evalctx ; // unusued parameter
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2009-06-20 23:00:19 +04:00
}
2011-09-03 08:10:36 +04:00
std : : string AbstractFunction : : dump ( const std : : string & indent , const std : : string & name ) const
2009-06-21 10:53:46 +04:00
{
2011-09-03 08:10:36 +04:00
std : : stringstream dump ;
dump < < indent < < " abstract function " < < name < < " (); \n " ;
return dump . str ( ) ;
2009-06-21 10:53:46 +04:00
}
2014-11-27 00:53:10 +03:00
Function : : Function ( const char * name , AssignmentList & definition_arguments , Expression * expr )
: name ( name ) , definition_arguments ( definition_arguments ) , expr ( expr )
{
}
2009-06-20 23:00:19 +04:00
Function : : ~ Function ( )
{
2009-06-21 10:53:46 +04:00
delete expr ;
2009-06-20 23:00:19 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr Function : : evaluate ( const Context * ctx , const EvalContext * evalctx ) const
2009-06-20 23:00:19 +04:00
{
2014-11-23 08:59:17 +03:00
if ( ! expr ) return ValuePtr : : undefined ;
2014-11-25 23:53:44 +03:00
Context c ( ctx ) ;
c . setVariables ( definition_arguments , evalctx ) ;
ValuePtr result = expr - > evaluate ( & c ) ;
2014-11-24 02:51:00 +03:00
2014-11-23 22:29:33 +03:00
return result ;
2009-06-21 10:53:46 +04:00
}
2011-09-03 08:10:36 +04:00
std : : string Function : : dump ( const std : : string & indent , const std : : string & name ) const
2009-06-21 10:53:46 +04:00
{
2011-09-03 08:10:36 +04:00
std : : stringstream dump ;
dump < < indent < < " function " < < name < < " ( " ;
2013-04-19 02:34:14 +04:00
for ( size_t i = 0 ; i < definition_arguments . size ( ) ; i + + ) {
const Assignment & arg = definition_arguments [ i ] ;
2011-09-03 08:10:36 +04:00
if ( i > 0 ) dump < < " , " ;
2013-04-19 02:34:14 +04:00
dump < < arg . first ;
if ( arg . second ) dump < < " = " < < * arg . second ;
2009-06-21 10:53:46 +04:00
}
2011-09-03 08:10:36 +04:00
dump < < " ) = " < < * expr < < " ; \n " ;
return dump . str ( ) ;
2009-06-20 23:00:19 +04:00
}
2014-11-27 00:53:10 +03:00
class FunctionTailRecursion : public Function
{
private :
bool invert ;
ExpressionFunctionCall * call ; // memory owned by the main expression
Expression * endexpr ; // memory owned by the main expression
public :
FunctionTailRecursion ( const char * name , AssignmentList & definition_arguments , Expression * expr , ExpressionFunctionCall * call , Expression * endexpr , bool invert ) ;
virtual ~ FunctionTailRecursion ( ) ;
virtual ValuePtr evaluate ( const Context * ctx , const EvalContext * evalctx ) const ;
} ;
FunctionTailRecursion : : FunctionTailRecursion ( const char * name , AssignmentList & definition_arguments , Expression * expr , ExpressionFunctionCall * call , Expression * endexpr , bool invert )
: Function ( name , definition_arguments , expr ) , invert ( invert ) , call ( call ) , endexpr ( endexpr )
{
}
FunctionTailRecursion : : ~ FunctionTailRecursion ( )
{
}
ValuePtr FunctionTailRecursion : : evaluate ( const Context * ctx , const EvalContext * evalctx ) const
{
if ( ! expr ) return ValuePtr : : undefined ;
Context c ( ctx ) ;
c . setVariables ( definition_arguments , evalctx ) ;
EvalContext ec ( & c , call - > call_arguments ) ;
2014-12-02 00:52:04 +03:00
Context tmp ( & c ) ;
2014-12-12 00:09:55 +03:00
unsigned int counter = 0 ;
2014-11-27 00:53:10 +03:00
while ( invert ^ expr - > first - > evaluate ( & c ) ) {
tmp . setVariables ( definition_arguments , & ec ) ;
c . apply_variables ( tmp ) ;
2014-12-12 00:09:55 +03:00
2015-02-11 02:59:11 +03:00
if ( counter + + = = 1000000 ) throw RecursionException : : create ( " function " , this - > name ) ;
2014-11-27 00:53:10 +03:00
}
ValuePtr result = endexpr - > evaluate ( & c ) ;
return result ;
}
Function * Function : : create ( const char * name , AssignmentList & definition_arguments , Expression * expr )
{
if ( dynamic_cast < ExpressionTernary * > ( expr ) ) {
ExpressionFunctionCall * f1 = dynamic_cast < ExpressionFunctionCall * > ( expr - > second ) ;
ExpressionFunctionCall * f2 = dynamic_cast < ExpressionFunctionCall * > ( expr - > third ) ;
if ( f1 & & ! f2 ) {
if ( name = = f1 - > funcname ) {
return new FunctionTailRecursion ( name , definition_arguments , expr , f1 , expr - > third , false ) ;
}
} else if ( f2 & & ! f1 ) {
if ( name = = f2 - > funcname ) {
return new FunctionTailRecursion ( name , definition_arguments , expr , f2 , expr - > second , true ) ;
}
}
}
return new Function ( name , definition_arguments , expr ) ;
}
2009-06-20 23:00:19 +04:00
BuiltinFunction : : ~ BuiltinFunction ( )
{
}
2014-11-23 08:59:17 +03:00
ValuePtr BuiltinFunction : : evaluate ( const Context * ctx , const EvalContext * evalctx ) const
2009-06-20 23:00:19 +04:00
{
2013-04-09 08:28:16 +04:00
return eval_func ( ctx , evalctx ) ;
2009-06-20 23:00:19 +04:00
}
2011-09-03 08:10:36 +04:00
std : : string BuiltinFunction : : dump ( const std : : string & indent , const std : : string & name ) const
2009-06-21 10:53:46 +04:00
{
2011-09-03 08:10:36 +04:00
std : : stringstream dump ;
dump < < indent < < " builtin function " < < name < < " (); \n " ;
return dump . str ( ) ;
2009-06-21 10:53:46 +04:00
}
2012-01-08 21:31:09 +04:00
static inline double deg2rad ( double x )
2009-06-30 22:05:10 +04:00
{
2012-01-08 21:31:09 +04:00
return x * M_PI / 180.0 ;
2009-06-30 22:05:10 +04:00
}
2012-01-08 21:31:09 +04:00
static inline double rad2deg ( double x )
2009-06-30 22:05:10 +04:00
{
2012-01-08 21:31:09 +04:00
return x * 180.0 / M_PI ;
2009-06-30 22:05:10 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_abs ( const Context * , const EvalContext * evalctx )
2010-02-26 14:53:32 +03:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( fabs ( v - > toDouble ( ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-02-26 14:53:32 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_sign ( const Context * , const EvalContext * evalctx )
2010-07-09 13:35:19 +04:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER ) {
register double x = v - > toDouble ( ) ;
return ValuePtr ( ( x < 0 ) ? - 1.0 : ( ( x > 0 ) ? 1.0 : 0.0 ) ) ;
2014-04-25 10:46:45 +04:00
}
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-07-09 13:35:19 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_rands ( const Context * , const EvalContext * evalctx )
2010-10-31 05:51:11 +03:00
{
2014-04-25 10:46:45 +04:00
size_t n = evalctx - > numArgs ( ) ;
if ( n = = 3 | | n = = 4 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v0 = evalctx - > getArgValue ( 0 ) ;
if ( v0 - > type ( ) ! = Value : : NUMBER ) goto quit ;
double min = v0 - > toDouble ( ) ;
2014-04-25 10:46:45 +04:00
2014-11-23 08:59:17 +03:00
ValuePtr v1 = evalctx - > getArgValue ( 1 ) ;
if ( v1 - > type ( ) ! = Value : : NUMBER ) goto quit ;
double max = v1 - > toDouble ( ) ;
2014-04-25 10:46:45 +04:00
if ( max < min ) {
register double tmp = min ; min = max ; max = tmp ;
}
2014-11-23 08:59:17 +03:00
ValuePtr v2 = evalctx - > getArgValue ( 2 ) ;
if ( v2 - > type ( ) ! = Value : : NUMBER ) goto quit ;
size_t numresults = std : : max ( 0 , static_cast < int > ( v2 - > toDouble ( ) ) ) ;
2014-04-25 10:46:45 +04:00
bool deterministic = false ;
if ( n > 3 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v3 = evalctx - > getArgValue ( 3 ) ;
if ( v3 - > type ( ) ! = Value : : NUMBER ) goto quit ;
deterministic_rng . seed ( ( unsigned int ) v3 - > toDouble ( ) ) ;
2014-04-25 10:46:45 +04:00
deterministic = true ;
}
Value : : VectorType vec ;
2015-01-29 20:59:56 +03:00
if ( min = = max ) { // Boost doesn't allow min == max
2014-04-25 10:46:45 +04:00
for ( size_t i = 0 ; i < numresults ; i + + )
vec . push_back ( Value ( min ) ) ;
} else {
2015-01-29 20:59:56 +03:00
boost : : uniform_real < > distributor ( min , max ) ;
2014-04-25 10:46:45 +04:00
for ( size_t i = 0 ; i < numresults ; i + + ) {
if ( deterministic ) {
2014-11-23 08:59:17 +03:00
vec . push_back ( Value ( distributor ( deterministic_rng ) ) ) ;
2014-04-25 10:46:45 +04:00
} else {
2014-11-23 08:59:17 +03:00
vec . push_back ( Value ( distributor ( lessdeterministic_rng ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2013-08-11 18:54:04 +04:00
}
2013-01-06 09:27:42 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( vec ) ;
2010-10-31 05:51:11 +03:00
}
2014-04-25 10:46:45 +04:00
quit :
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-10-31 05:51:11 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_min ( const Context * , const EvalContext * evalctx )
2010-01-06 22:58:54 +03:00
{
2014-04-25 10:46:45 +04:00
// preserve special handling of the first argument
// as a template for vector processing
size_t n = evalctx - > numArgs ( ) ;
if ( n > = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v0 = evalctx - > getArgValue ( 0 ) ;
2014-05-10 21:40:15 +04:00
2014-11-23 08:59:17 +03:00
if ( n = = 1 & & v0 - > type ( ) = = Value : : VECTOR & & ! v0 - > toVector ( ) . empty ( ) ) {
Value min = v0 - > toVector ( ) [ 0 ] ;
for ( size_t i = 1 ; i < v0 - > toVector ( ) . size ( ) ; i + + ) {
if ( v0 - > toVector ( ) [ i ] < min ) min = v0 - > toVector ( ) [ i ] ;
2014-05-10 21:40:15 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( min ) ;
2014-05-10 21:40:15 +04:00
}
2014-11-23 08:59:17 +03:00
if ( v0 - > type ( ) = = Value : : NUMBER ) {
double val = v0 - > toDouble ( ) ;
2014-04-25 10:46:45 +04:00
for ( size_t i = 1 ; i < n ; + + i ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( i ) ;
2014-04-25 10:46:45 +04:00
// 4/20/14 semantic change per discussion:
// break on any non-number
2014-11-23 08:59:17 +03:00
if ( v - > type ( ) ! = Value : : NUMBER ) goto quit ;
register double x = v - > toDouble ( ) ;
2014-04-25 10:46:45 +04:00
if ( x < val ) val = x ;
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( val ) ;
2014-04-16 00:36:02 +04:00
}
2010-01-06 22:58:54 +03:00
}
2014-04-25 10:46:45 +04:00
quit :
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-01-06 22:58:54 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_max ( const Context * , const EvalContext * evalctx )
2010-01-06 22:58:54 +03:00
{
2014-04-25 10:46:45 +04:00
// preserve special handling of the first argument
// as a template for vector processing
size_t n = evalctx - > numArgs ( ) ;
if ( n > = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v0 = evalctx - > getArgValue ( 0 ) ;
2014-05-10 21:40:15 +04:00
2014-11-23 08:59:17 +03:00
if ( n = = 1 & & v0 - > type ( ) = = Value : : VECTOR & & ! v0 - > toVector ( ) . empty ( ) ) {
Value max = v0 - > toVector ( ) [ 0 ] ;
for ( size_t i = 1 ; i < v0 - > toVector ( ) . size ( ) ; i + + ) {
if ( v0 - > toVector ( ) [ i ] > max ) max = v0 - > toVector ( ) [ i ] ;
2014-05-10 21:40:15 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( max ) ;
2014-05-10 21:40:15 +04:00
}
2014-11-23 08:59:17 +03:00
if ( v0 - > type ( ) = = Value : : NUMBER ) {
double val = v0 - > toDouble ( ) ;
2014-04-25 10:46:45 +04:00
for ( size_t i = 1 ; i < n ; + + i ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( i ) ;
2014-04-25 10:46:45 +04:00
// 4/20/14 semantic change per discussion:
// break on any non-number
2014-11-23 08:59:17 +03:00
if ( v - > type ( ) ! = Value : : NUMBER ) goto quit ;
register double x = v - > toDouble ( ) ;
2014-04-25 10:46:45 +04:00
if ( x > val ) val = x ;
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( val ) ;
2014-04-16 00:36:02 +04:00
}
2010-01-06 22:58:54 +03:00
}
2014-04-25 10:46:45 +04:00
quit :
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-01-06 22:58:54 +03:00
}
2014-04-25 10:46:45 +04:00
// this limit assumes 26+26=52 bits mantissa
// comment/undefine it to disable domain check
# define TRIG_HUGE_VAL ((1L<<26)*360.0*(1L<<26))
2014-06-04 14:04:21 +04:00
double sin_degrees ( register double x )
{
// use positive tests because of possible Inf/NaN
if ( x < 360.0 & & x > = 0.0 ) {
// Ok for now
} else
# ifdef TRIG_HUGE_VAL
if ( x < TRIG_HUGE_VAL & & x > - TRIG_HUGE_VAL )
# endif
{
register double revolutions = floor ( x / 360.0 ) ;
x - = 360.0 * revolutions ;
}
# ifdef TRIG_HUGE_VAL
else {
// total loss of computational accuracy
// the result would be meaningless
return std : : numeric_limits < double > : : quiet_NaN ( ) ;
}
# endif
register bool oppose = x > = 180.0 ;
if ( oppose ) x - = 180.0 ;
if ( x > 90.0 ) x = 180.0 - x ;
if ( x < 45.0 ) {
if ( x = = 30.0 ) x = 0.5 ;
else x = sin ( deg2rad ( x ) ) ;
} else if ( x = = 45.0 )
x = M_SQRT1_2 ;
else // Inf/Nan would fall here
x = cos ( deg2rad ( 90.0 - x ) ) ;
return oppose ? - x : x ;
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_sin ( const Context * , const EvalContext * evalctx )
2009-06-20 23:00:19 +04:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( sin_degrees ( v - > toDouble ( ) ) ) ;
2014-06-04 14:04:21 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2014-06-04 14:04:21 +04:00
}
double cos_degrees ( register double x )
{
// use positive tests because of possible Inf/NaN
if ( x < 360.0 & & x > = 0.0 ) {
// Ok for now
} else
2014-04-25 10:46:45 +04:00
# ifdef TRIG_HUGE_VAL
2014-06-04 14:04:21 +04:00
if ( x < TRIG_HUGE_VAL & & x > - TRIG_HUGE_VAL )
2014-04-25 10:46:45 +04:00
# endif
2014-06-04 14:04:21 +04:00
{
register double revolutions = floor ( x / 360.0 ) ;
x - = 360.0 * revolutions ;
}
2014-04-25 10:46:45 +04:00
# ifdef TRIG_HUGE_VAL
2014-06-04 14:04:21 +04:00
else {
// total loss of computational accuracy
// the result would be meaningless
return std : : numeric_limits < double > : : quiet_NaN ( ) ;
}
2014-04-25 10:46:45 +04:00
# endif
2014-06-04 14:04:21 +04:00
register bool oppose = x > = 180.0 ;
if ( oppose ) x - = 180.0 ;
if ( x > 90.0 ) {
x = 180.0 - x ;
oppose = ! oppose ;
2014-04-25 10:46:45 +04:00
}
2014-06-04 14:04:21 +04:00
if ( x > 45.0 ) {
if ( x = = 60.0 ) x = 0.5 ;
else x = sin ( deg2rad ( 90.0 - x ) ) ;
} else if ( x = = 45.0 )
x = M_SQRT1_2 ;
else // Inf/Nan would fall here
x = cos ( deg2rad ( x ) ) ;
return oppose ? - x : x ;
2009-06-20 23:00:19 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_cos ( const Context * , const EvalContext * evalctx )
2009-06-20 23:00:19 +04:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( cos_degrees ( v - > toDouble ( ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2009-06-20 23:00:19 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_asin ( const Context * , const EvalContext * evalctx )
2009-06-20 23:00:19 +04:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( rad2deg ( asin ( v - > toDouble ( ) ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2009-06-20 23:00:19 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_acos ( const Context * , const EvalContext * evalctx )
2009-06-20 23:00:19 +04:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( rad2deg ( acos ( v - > toDouble ( ) ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2009-06-20 23:00:19 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_tan ( const Context * , const EvalContext * evalctx )
2009-06-20 23:00:19 +04:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( tan ( deg2rad ( v - > toDouble ( ) ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2009-06-20 23:00:19 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_atan ( const Context * , const EvalContext * evalctx )
2009-06-20 23:00:19 +04:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( rad2deg ( atan ( v - > toDouble ( ) ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2009-06-20 23:00:19 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_atan2 ( const Context * , const EvalContext * evalctx )
2009-06-20 23:00:19 +04:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 2 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v0 = evalctx - > getArgValue ( 0 ) , v1 = evalctx - > getArgValue ( 1 ) ;
if ( v0 - > type ( ) = = Value : : NUMBER & & v1 - > type ( ) = = Value : : NUMBER )
return ValuePtr ( rad2deg ( atan2 ( v0 - > toDouble ( ) , v1 - > toDouble ( ) ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2009-06-20 23:00:19 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_pow ( const Context * , const EvalContext * evalctx )
2010-01-31 04:42:17 +03:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 2 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v0 = evalctx - > getArgValue ( 0 ) , v1 = evalctx - > getArgValue ( 1 ) ;
if ( v0 - > type ( ) = = Value : : NUMBER & & v1 - > type ( ) = = Value : : NUMBER )
return ValuePtr ( pow ( v0 - > toDouble ( ) , v1 - > toDouble ( ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-01-31 04:42:17 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_round ( const Context * , const EvalContext * evalctx )
2010-01-31 04:42:17 +03:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( round ( v - > toDouble ( ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-01-31 04:42:17 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_ceil ( const Context * , const EvalContext * evalctx )
2010-01-31 04:42:17 +03:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( ceil ( v - > toDouble ( ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-01-31 04:42:17 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_floor ( const Context * , const EvalContext * evalctx )
2010-02-21 11:16:09 +03:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( floor ( v - > toDouble ( ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-02-21 11:16:09 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_sqrt ( const Context * , const EvalContext * evalctx )
2010-02-10 20:27:08 +03:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( sqrt ( v - > toDouble ( ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-02-10 20:27:08 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_exp ( const Context * , const EvalContext * evalctx )
2010-02-21 11:16:09 +03:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( exp ( v - > toDouble ( ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-02-21 11:16:09 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_length ( const Context * , const EvalContext * evalctx )
2011-11-12 23:42:27 +04:00
{
2013-04-19 05:42:33 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : VECTOR ) return ValuePtr ( int ( v - > toVector ( ) . size ( ) ) ) ;
if ( v - > type ( ) = = Value : : STRING ) {
2013-12-05 10:56:54 +04:00
//Unicode glyph count for the length -- rather than the string (num. of bytes) length.
2014-11-23 08:59:17 +03:00
std : : string text = v - > toString ( ) ;
return ValuePtr ( int ( g_utf8_strlen ( text . c_str ( ) , text . size ( ) ) ) ) ;
2013-12-05 10:56:54 +04:00
}
2011-11-12 23:42:27 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2011-11-12 23:42:27 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_log ( const Context * , const EvalContext * evalctx )
2010-02-21 11:16:09 +03:00
{
2014-04-25 10:46:45 +04:00
size_t n = evalctx - > numArgs ( ) ;
if ( n = = 1 | | n = = 2 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v0 = evalctx - > getArgValue ( 0 ) ;
if ( v0 - > type ( ) = = Value : : NUMBER ) {
double x = 10.0 , y = v0 - > toDouble ( ) ;
2014-04-25 10:46:45 +04:00
if ( n > 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v1 = evalctx - > getArgValue ( 1 ) ;
if ( v1 - > type ( ) ! = Value : : NUMBER ) goto quit ;
x = y ; y = v1 - > toDouble ( ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( log ( y ) / log ( x ) ) ;
2014-04-25 10:46:45 +04:00
}
}
quit :
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-02-21 11:16:09 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_ln ( const Context * , const EvalContext * evalctx )
2010-02-21 11:16:09 +03:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) = = Value : : NUMBER )
return ValuePtr ( log ( v - > toDouble ( ) ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2010-02-21 11:16:09 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_str ( const Context * , const EvalContext * evalctx )
2009-11-26 14:54:28 +03:00
{
2010-11-08 00:29:34 +03:00
std : : stringstream stream ;
2013-04-19 05:42:33 +04:00
for ( size_t i = 0 ; i < evalctx - > numArgs ( ) ; i + + ) {
2014-11-23 08:59:17 +03:00
stream < < evalctx - > getArgValue ( i ) - > toString ( ) ;
2009-11-26 14:54:28 +03:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( stream . str ( ) ) ;
2009-11-26 14:54:28 +03:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_chr ( const Context * , const EvalContext * evalctx )
2014-07-13 20:43:44 +04:00
{
std : : stringstream stream ;
for ( size_t i = 0 ; i < evalctx - > numArgs ( ) ; i + + ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( i ) ;
stream < < v - > chrString ( ) ;
2014-07-13 20:43:44 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( stream . str ( ) ) ;
2014-07-13 20:43:44 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_concat ( const Context * , const EvalContext * evalctx )
2013-12-26 08:01:40 +04:00
{
Value : : VectorType result ;
for ( size_t i = 0 ; i < evalctx - > numArgs ( ) ; i + + ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( i ) ;
if ( v - > type ( ) = = Value : : VECTOR ) {
Value : : VectorType vec = v - > toVector ( ) ;
2013-12-26 08:01:40 +04:00
for ( Value : : VectorType : : const_iterator it = vec . begin ( ) ; it ! = vec . end ( ) ; it + + ) {
result . push_back ( * it ) ;
}
} else {
2014-11-23 08:59:17 +03:00
result . push_back ( * v ) ;
2013-12-26 08:01:40 +04:00
}
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( result ) ;
2013-12-26 08:01:40 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_lookup ( const Context * , const EvalContext * evalctx )
2010-01-13 20:03:32 +03:00
{
double p , low_p , low_v , high_p , high_v ;
2013-04-19 05:42:33 +04:00
if ( evalctx - > numArgs ( ) < 2 | | // Needs two args
2014-11-23 08:59:17 +03:00
! evalctx - > getArgValue ( 0 ) - > getDouble ( p ) ) // First must be a number
return ValuePtr : : undefined ;
2014-06-04 14:04:21 +04:00
2014-11-23 08:59:17 +03:00
ValuePtr v1 = evalctx - > getArgValue ( 1 ) ;
const Value : : VectorType & vec = v1 - > toVector ( ) ;
2014-06-04 14:04:21 +04:00
if ( vec [ 0 ] . toVector ( ) . size ( ) < 2 ) // Second must be a vector of vectors
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2014-06-04 14:04:21 +04:00
if ( ! vec [ 0 ] . getVec2 ( low_p , low_v ) | | ! vec [ 0 ] . getVec2 ( high_p , high_v ) )
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2014-06-04 14:04:21 +04:00
for ( size_t i = 1 ; i < vec . size ( ) ; i + + ) {
2010-01-13 20:03:32 +03:00
double this_p , this_v ;
2014-06-04 14:04:21 +04:00
if ( vec [ i ] . getVec2 ( this_p , this_v ) ) {
2010-01-13 20:03:32 +03:00
if ( this_p < = p & & ( this_p > low_p | | low_p > p ) ) {
low_p = this_p ;
low_v = this_v ;
}
if ( this_p > = p & & ( this_p < high_p | | high_p < p ) ) {
high_p = this_p ;
high_v = this_v ;
}
}
}
if ( p < = low_p )
2014-11-23 08:59:17 +03:00
return ValuePtr ( high_v ) ;
2013-05-09 18:40:01 +04:00
if ( p > = high_p )
2014-11-23 08:59:17 +03:00
return ValuePtr ( low_v ) ;
2010-01-13 20:03:32 +03:00
double f = ( p - low_p ) / ( high_p - low_p ) ;
2014-11-23 08:59:17 +03:00
return ValuePtr ( high_v * f + low_v * ( 1 - f ) ) ;
2010-01-13 20:03:32 +03:00
}
2012-02-15 08:04:40 +04:00
/*
Pattern :
" search " " ( " ( match_value | list_of_match_values ) " , " vector_of_vectors
( " , " num_returns_per_match
( " , " index_col_num ) ? ) ?
" ) " ;
match_value : ( Value : : NUMBER | Value : : STRING ) ;
list_of_values : " [ " match_value ( " , " match_value ) * " ] " ;
vector_of_vectors : " [ " ( " [ " Value ( " , " Value ) * " ] " ) + " ] " ;
num_returns_per_match : int ;
index_col_num : int ;
2013-12-05 10:56:54 +04:00
The search string and searched strings can be unicode strings .
2012-02-15 08:04:40 +04:00
Examples :
Index values return as list :
search ( " a " , " abcdabcd " ) ;
2013-12-05 10:56:54 +04:00
- returns [ 0 ]
search ( " Л " , " Л " ) ; //A unicode string
- returns [ 0 ]
search ( " 🂡aЛ " , " a🂡Л🂡a🂡Л🂡a " , 0 ) ;
- returns [[1,3,5,7],[0,4,8],[2,6]]
search ( " a " , " abcdabcd " , 0 ) ; //Search up to all matches
- returns [[0,4]]
2012-02-15 08:04:40 +04:00
search ( " a " , " abcdabcd " , 1 ) ;
- returns [ 0 ]
search ( " e " , " abcdabcd " , 1 ) ;
- returns [ ]
search ( " a " , [ [ " a " , 1 ] , [ " b " , 2 ] , [ " c " , 3 ] , [ " d " , 4 ] , [ " a " , 5 ] , [ " b " , 6 ] , [ " c " , 7 ] , [ " d " , 8 ] , [ " e " , 9 ] ] ) ;
- returns [ 0 , 4 ]
Search on different column ; return Index values :
search ( 3 , [ [ " a " , 1 ] , [ " b " , 2 ] , [ " c " , 3 ] , [ " d " , 4 ] , [ " a " , 5 ] , [ " b " , 6 ] , [ " c " , 7 ] , [ " d " , 8 ] , [ " e " , 3 ] ] , 0 , 1 ) ;
- returns [ 0 , 8 ]
Search on list of values :
Return all matches per search vector element :
search ( " abc " , [ [ " a " , 1 ] , [ " b " , 2 ] , [ " c " , 3 ] , [ " d " , 4 ] , [ " a " , 5 ] , [ " b " , 6 ] , [ " c " , 7 ] , [ " d " , 8 ] , [ " e " , 9 ] ] , 0 ) ;
- returns [[0,4],[1,5],[2,6]]
Return first match per search vector element ; special case return vector :
search ( " abc " , [ [ " a " , 1 ] , [ " b " , 2 ] , [ " c " , 3 ] , [ " d " , 4 ] , [ " a " , 5 ] , [ " b " , 6 ] , [ " c " , 7 ] , [ " d " , 8 ] , [ " e " , 9 ] ] , 1 ) ;
- returns [ 0 , 1 , 2 ]
Return first two matches per search vector element ; vector of vectors :
search ( " abce " , [ [ " a " , 1 ] , [ " b " , 2 ] , [ " c " , 3 ] , [ " d " , 4 ] , [ " a " , 5 ] , [ " b " , 6 ] , [ " c " , 7 ] , [ " d " , 8 ] , [ " e " , 9 ] ] , 2 ) ;
- returns [[0,4],[1,5],[2,6],[8]]
*/
2014-05-25 08:50:19 +04:00
static Value : : VectorType search ( const std : : string & find , const std : : string & table ,
2015-01-09 00:11:45 +03:00
unsigned int num_returns_per_match )
2014-05-25 08:50:19 +04:00
{
Value : : VectorType returnvec ;
//Unicode glyph count for the length
size_t findThisSize = g_utf8_strlen ( find . c_str ( ) , find . size ( ) ) ;
size_t searchTableSize = g_utf8_strlen ( table . c_str ( ) , table . size ( ) ) ;
for ( size_t i = 0 ; i < findThisSize ; i + + ) {
unsigned int matchCount = 0 ;
Value : : VectorType resultvec ;
2014-06-04 14:04:21 +04:00
const gchar * ptr_ft = g_utf8_offset_to_pointer ( find . c_str ( ) , i ) ;
2014-05-25 08:50:19 +04:00
for ( size_t j = 0 ; j < searchTableSize ; j + + ) {
const gchar * ptr_st = g_utf8_offset_to_pointer ( table . c_str ( ) , j ) ;
if ( ptr_ft & & ptr_st & & ( g_utf8_get_char ( ptr_ft ) = = g_utf8_get_char ( ptr_st ) ) ) {
matchCount + + ;
if ( num_returns_per_match = = 1 ) {
returnvec . push_back ( Value ( double ( j ) ) ) ;
break ;
} else {
resultvec . push_back ( Value ( double ( j ) ) ) ;
}
if ( num_returns_per_match > 1 & & matchCount > = num_returns_per_match ) {
break ;
}
}
}
if ( matchCount = = 0 ) {
gchar utf8_of_cp [ 6 ] = " " ; //A buffer for a single unicode character to be copied into
if ( ptr_ft ) g_utf8_strncpy ( utf8_of_cp , ptr_ft , 1 ) ;
}
if ( num_returns_per_match = = 0 | | num_returns_per_match > 1 ) {
returnvec . push_back ( Value ( resultvec ) ) ;
}
}
return returnvec ;
}
static Value : : VectorType search ( const std : : string & find , const Value : : VectorType & table ,
unsigned int num_returns_per_match , unsigned int index_col_num )
{
Value : : VectorType returnvec ;
//Unicode glyph count for the length
unsigned int findThisSize = g_utf8_strlen ( find . c_str ( ) , find . size ( ) ) ;
unsigned int searchTableSize = table . size ( ) ;
for ( size_t i = 0 ; i < findThisSize ; i + + ) {
unsigned int matchCount = 0 ;
Value : : VectorType resultvec ;
2014-06-04 14:04:21 +04:00
const gchar * ptr_ft = g_utf8_offset_to_pointer ( find . c_str ( ) , i ) ;
2014-05-25 08:50:19 +04:00
for ( size_t j = 0 ; j < searchTableSize ; j + + ) {
2015-01-09 00:11:45 +03:00
Value : : VectorType entryVec = table [ j ] . toVector ( ) ;
if ( entryVec . size ( ) < = index_col_num ) {
PRINTB ( " WARNING: Invalid entry in search vector at index %d, required number of values in the entry: %d. Invalid entry: %s " , j % ( index_col_num + 1 ) % table [ j ] ) ;
return Value : : VectorType ( ) ;
}
const gchar * ptr_st = g_utf8_offset_to_pointer ( entryVec [ index_col_num ] . toString ( ) . c_str ( ) , 0 ) ;
2014-05-25 08:50:19 +04:00
if ( ptr_ft & & ptr_st & & ( g_utf8_get_char ( ptr_ft ) = = g_utf8_get_char ( ptr_st ) ) ) {
matchCount + + ;
if ( num_returns_per_match = = 1 ) {
returnvec . push_back ( Value ( double ( j ) ) ) ;
break ;
} else {
resultvec . push_back ( Value ( double ( j ) ) ) ;
}
if ( num_returns_per_match > 1 & & matchCount > = num_returns_per_match ) {
break ;
}
}
}
if ( matchCount = = 0 ) {
gchar utf8_of_cp [ 6 ] = " " ; //A buffer for a single unicode character to be copied into
if ( ptr_ft ) g_utf8_strncpy ( utf8_of_cp , ptr_ft , 1 ) ;
PRINTB ( " WARNING: search term not found: \" %s \" " , utf8_of_cp ) ;
}
if ( num_returns_per_match = = 0 | | num_returns_per_match > 1 ) {
returnvec . push_back ( Value ( resultvec ) ) ;
}
}
return returnvec ;
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_search ( const Context * , const EvalContext * evalctx )
2012-02-15 08:04:40 +04:00
{
2014-11-23 08:59:17 +03:00
if ( evalctx - > numArgs ( ) < 2 ) return ValuePtr : : undefined ;
2012-02-18 16:44:24 +04:00
2014-11-23 08:59:17 +03:00
ValuePtr findThis = evalctx - > getArgValue ( 0 ) ;
ValuePtr searchTable = evalctx - > getArgValue ( 1 ) ;
unsigned int num_returns_per_match = ( evalctx - > numArgs ( ) > 2 ) ? evalctx - > getArgValue ( 2 ) - > toDouble ( ) : 1 ;
unsigned int index_col_num = ( evalctx - > numArgs ( ) > 3 ) ? evalctx - > getArgValue ( 3 ) - > toDouble ( ) : 0 ;
2012-02-18 16:44:24 +04:00
2012-03-28 02:05:00 +04:00
Value : : VectorType returnvec ;
2012-02-18 16:44:24 +04:00
2014-11-23 08:59:17 +03:00
if ( findThis - > type ( ) = = Value : : NUMBER ) {
2012-02-18 16:44:24 +04:00
unsigned int matchCount = 0 ;
search(): fix crash bug and add additional feature
search(4,[1,2,3]) crashed OpenSCAD. Instead of crashing, one can now search vectors for matching elements.
In addition, search([[1,2]],[[0,1],[1,2],[2,3]]) will work and return [1].
2014-05-10 21:46:12 +04:00
2014-11-23 08:59:17 +03:00
for ( size_t j = 0 ; j < searchTable - > toVector ( ) . size ( ) ; j + + ) {
const Value & search_element = searchTable - > toVector ( ) [ j ] ;
search(): fix crash bug and add additional feature
search(4,[1,2,3]) crashed OpenSCAD. Instead of crashing, one can now search vectors for matching elements.
In addition, search([[1,2]],[[0,1],[1,2],[2,3]]) will work and return [1].
2014-05-10 21:46:12 +04:00
2014-11-23 08:59:17 +03:00
if ( ( index_col_num = = 0 & & * findThis = = search_element ) | |
2014-06-04 14:04:21 +04:00
( index_col_num < search_element . toVector ( ) . size ( ) & &
2014-11-23 08:59:17 +03:00
* findThis = = search_element . toVector ( ) [ index_col_num ] ) ) {
search(): fix crash bug and add additional feature
search(4,[1,2,3]) crashed OpenSCAD. Instead of crashing, one can now search vectors for matching elements.
In addition, search([[1,2]],[[0,1],[1,2],[2,3]]) will work and return [1].
2014-05-10 21:46:12 +04:00
returnvec . push_back ( Value ( double ( j ) ) ) ;
matchCount + + ;
if ( num_returns_per_match ! = 0 & & matchCount > = num_returns_per_match ) break ;
}
2012-02-15 08:04:40 +04:00
}
2014-11-23 08:59:17 +03:00
} else if ( findThis - > type ( ) = = Value : : STRING ) {
if ( searchTable - > type ( ) = = Value : : STRING ) {
2015-01-09 00:11:45 +03:00
returnvec = search ( findThis - > toString ( ) , searchTable - > toString ( ) , num_returns_per_match ) ;
2013-12-05 10:56:54 +04:00
}
2014-05-25 08:50:19 +04:00
else {
2014-11-23 08:59:17 +03:00
returnvec = search ( findThis - > toString ( ) , searchTable - > toVector ( ) , num_returns_per_match , index_col_num ) ;
2012-02-15 08:04:40 +04:00
}
2014-11-23 08:59:17 +03:00
} else if ( findThis - > type ( ) = = Value : : VECTOR ) {
for ( size_t i = 0 ; i < findThis - > toVector ( ) . size ( ) ; i + + ) {
2012-02-18 16:44:24 +04:00
unsigned int matchCount = 0 ;
2012-03-28 02:05:00 +04:00
Value : : VectorType resultvec ;
search(): fix crash bug and add additional feature
search(4,[1,2,3]) crashed OpenSCAD. Instead of crashing, one can now search vectors for matching elements.
In addition, search([[1,2]],[[0,1],[1,2],[2,3]]) will work and return [1].
2014-05-10 21:46:12 +04:00
2014-11-23 08:59:17 +03:00
Value const & find_value = findThis - > toVector ( ) [ i ] ;
search(): fix crash bug and add additional feature
search(4,[1,2,3]) crashed OpenSCAD. Instead of crashing, one can now search vectors for matching elements.
In addition, search([[1,2]],[[0,1],[1,2],[2,3]]) will work and return [1].
2014-05-10 21:46:12 +04:00
2014-11-23 08:59:17 +03:00
for ( size_t j = 0 ; j < searchTable - > toVector ( ) . size ( ) ; j + + ) {
search(): fix crash bug and add additional feature
search(4,[1,2,3]) crashed OpenSCAD. Instead of crashing, one can now search vectors for matching elements.
In addition, search([[1,2]],[[0,1],[1,2],[2,3]]) will work and return [1].
2014-05-10 21:46:12 +04:00
2014-11-23 08:59:17 +03:00
Value const & search_element = searchTable - > toVector ( ) [ j ] ;
search(): fix crash bug and add additional feature
search(4,[1,2,3]) crashed OpenSCAD. Instead of crashing, one can now search vectors for matching elements.
In addition, search([[1,2]],[[0,1],[1,2],[2,3]]) will work and return [1].
2014-05-10 21:46:12 +04:00
2014-06-04 14:04:21 +04:00
if ( ( index_col_num = = 0 & & find_value = = search_element ) | |
( index_col_num < search_element . toVector ( ) . size ( ) & &
find_value = = search_element . toVector ( ) [ index_col_num ] ) ) {
2012-03-28 02:05:00 +04:00
Value resultValue ( ( double ( j ) ) ) ;
2012-02-15 08:04:40 +04:00
matchCount + + ;
2012-03-28 02:05:00 +04:00
if ( num_returns_per_match = = 1 ) {
returnvec . push_back ( resultValue ) ;
2012-02-18 16:44:24 +04:00
break ;
2012-02-15 08:04:40 +04:00
} else {
2012-03-28 02:05:00 +04:00
resultvec . push_back ( resultValue ) ;
2012-02-15 08:04:40 +04:00
}
2012-02-18 16:44:24 +04:00
if ( num_returns_per_match > 1 & & matchCount > = num_returns_per_match ) break ;
2012-02-15 08:04:40 +04:00
}
}
2012-02-18 16:44:24 +04:00
if ( num_returns_per_match = = 1 & & matchCount = = 0 ) {
2014-11-23 08:59:17 +03:00
returnvec . push_back ( resultvec ) ;
2012-02-15 08:04:40 +04:00
}
2012-02-18 16:44:24 +04:00
if ( num_returns_per_match = = 0 | | num_returns_per_match > 1 ) {
2014-11-23 08:59:17 +03:00
returnvec . push_back ( resultvec ) ;
2012-02-18 16:44:24 +04:00
}
2012-02-15 08:04:40 +04:00
}
} else {
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2012-02-15 08:04:40 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( returnvec ) ;
2012-02-15 08:04:40 +04:00
}
2011-09-30 04:43:09 +04:00
# define QUOTE(x__) # x__
# define QUOTED(x__) QUOTE(x__)
2014-11-23 08:59:17 +03:00
ValuePtr builtin_version ( const Context * , const EvalContext * evalctx )
2011-09-30 04:43:09 +04:00
{
2013-05-20 08:31:18 +04:00
( void ) evalctx ; // unusued parameter
2012-03-28 02:05:00 +04:00
Value : : VectorType val ;
2014-11-23 08:59:17 +03:00
val . push_back ( double ( OPENSCAD_YEAR ) ) ;
val . push_back ( double ( OPENSCAD_MONTH ) ) ;
2011-10-04 02:09:04 +04:00
# ifdef OPENSCAD_DAY
2014-11-23 08:59:17 +03:00
val . push_back ( double ( OPENSCAD_DAY ) ) ;
2011-10-04 02:09:04 +04:00
# endif
2014-11-23 08:59:17 +03:00
return ValuePtr ( val ) ;
2011-10-04 02:09:04 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_version_num ( const Context * ctx , const EvalContext * evalctx )
2011-10-04 02:09:04 +04:00
{
2014-11-23 08:59:17 +03:00
ValuePtr val = ( evalctx - > numArgs ( ) = = 0 ) ? builtin_version ( ctx , evalctx ) : evalctx - > getArgValue ( 0 ) ;
2011-10-04 02:09:04 +04:00
double y , m , d = 0 ;
2014-11-23 08:59:17 +03:00
if ( ! val - > getVec3 ( y , m , d ) ) {
if ( ! val - > getVec2 ( y , m ) ) {
return ValuePtr : : undefined ;
2011-10-04 02:09:04 +04:00
}
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( y * 10000 + m * 100 + d ) ;
2011-09-30 04:43:09 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_parent_module ( const Context * , const EvalContext * evalctx )
2013-08-18 19:18:43 +04:00
{
int n ;
double d ;
int s = Module : : stack_size ( ) ;
if ( evalctx - > numArgs ( ) = = 0 )
d = 1 ; // parent module
2014-04-25 10:46:45 +04:00
else if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr v = evalctx - > getArgValue ( 0 ) ;
if ( v - > type ( ) ! = Value : : NUMBER ) return ValuePtr : : undefined ;
v - > getDouble ( d ) ;
2014-04-25 10:46:45 +04:00
} else
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2013-08-18 19:18:43 +04:00
n = trunc ( d ) ;
if ( n < 0 ) {
PRINTB ( " WARNING: Negative parent module index (%d) not allowed " , n ) ;
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2013-08-18 19:18:43 +04:00
}
if ( n > = s ) {
PRINTB ( " WARNING: Parent module index (%d) greater than the number of modules on the stack " , n ) ;
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2013-08-18 19:18:43 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( Module : : stack_element ( s - 1 - n ) ) ;
2013-08-18 19:18:43 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_norm ( const Context * , const EvalContext * evalctx )
2014-02-17 01:11:26 +04:00
{
2014-04-25 10:46:45 +04:00
if ( evalctx - > numArgs ( ) = = 1 ) {
2014-11-23 08:59:17 +03:00
ValuePtr val = evalctx - > getArgValue ( 0 ) ;
if ( val - > type ( ) = = Value : : VECTOR ) {
2014-04-25 10:46:45 +04:00
double sum = 0 ;
2014-11-23 08:59:17 +03:00
Value : : VectorType v = val - > toVector ( ) ;
2014-04-25 10:46:45 +04:00
size_t n = v . size ( ) ;
for ( size_t i = 0 ; i < n ; i + + )
if ( v [ i ] . type ( ) = = Value : : NUMBER ) {
// sum += pow(v[i].toDouble(),2);
register double x = v [ i ] . toDouble ( ) ;
sum + = x * x ;
} else {
2014-12-21 04:11:02 +03:00
PRINT ( " WARNING: Incorrect arguments to norm() " ) ;
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2014-04-25 10:46:45 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr ( sqrt ( sum ) ) ;
2014-04-25 10:46:45 +04:00
}
2014-02-17 01:11:26 +04:00
}
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2014-02-17 01:11:26 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr builtin_cross ( const Context * , const EvalContext * evalctx )
2014-02-17 02:04:48 +04:00
{
if ( evalctx - > numArgs ( ) ! = 2 ) {
PRINT ( " WARNING: Invalid number of parameters for cross() " ) ;
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2014-02-17 02:04:48 +04:00
}
2014-11-23 08:59:17 +03:00
ValuePtr arg0 = evalctx - > getArgValue ( 0 ) ;
ValuePtr arg1 = evalctx - > getArgValue ( 1 ) ;
if ( ( arg0 - > type ( ) ! = Value : : VECTOR ) | | ( arg1 - > type ( ) ! = Value : : VECTOR ) ) {
2014-02-17 02:04:48 +04:00
PRINT ( " WARNING: Invalid type of parameters for cross() " ) ;
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2014-02-17 02:04:48 +04:00
}
2014-11-23 08:59:17 +03:00
Value : : VectorType v0 = arg0 - > toVector ( ) ;
Value : : VectorType v1 = arg1 - > toVector ( ) ;
2015-03-03 10:28:01 +03:00
if ( ( v0 . size ( ) = = 2 ) & & ( v1 . size ( ) = = 2 ) ) {
return ValuePtr ( Value ( v0 [ 0 ] . toDouble ( ) * v1 [ 1 ] . toDouble ( ) - v0 [ 1 ] . toDouble ( ) * v1 [ 0 ] . toDouble ( ) ) ) ;
}
2014-02-17 02:04:48 +04:00
if ( ( v0 . size ( ) ! = 3 ) | | ( v1 . size ( ) ! = 3 ) ) {
PRINT ( " WARNING: Invalid vector size of parameter for cross() " ) ;
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2014-02-17 02:04:48 +04:00
}
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() " ) ;
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2014-02-17 02:04:48 +04:00
}
double d0 = v0 [ a ] . toDouble ( ) ;
double d1 = v1 [ a ] . toDouble ( ) ;
2014-03-04 08:37:25 +04:00
if ( boost : : math : : isnan ( d0 ) | | boost : : math : : isnan ( d1 ) ) {
2014-02-17 02:04:48 +04:00
PRINT ( " WARNING: Invalid value (NaN) in parameter vector for cross() " ) ;
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2014-02-17 02:04:48 +04:00
}
2014-03-04 08:37:25 +04:00
if ( boost : : math : : isinf ( d0 ) | | boost : : math : : isinf ( d1 ) ) {
2014-02-17 02:04:48 +04:00
PRINT ( " WARNING: Invalid value (INF) in parameter vector for cross() " ) ;
2014-11-23 08:59:17 +03:00
return ValuePtr : : undefined ;
2014-02-17 02:04:48 +04:00
}
}
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 ) ) ;
2014-11-23 08:59:17 +03:00
return ValuePtr ( result ) ;
2014-02-17 02:04:48 +04:00
}
2011-11-06 21:37:12 +04:00
void register_builtin_functions ( )
{
Builtins : : init ( " abs " , new BuiltinFunction ( & builtin_abs ) ) ;
Builtins : : init ( " sign " , new BuiltinFunction ( & builtin_sign ) ) ;
Builtins : : init ( " rands " , new BuiltinFunction ( & builtin_rands ) ) ;
Builtins : : init ( " min " , new BuiltinFunction ( & builtin_min ) ) ;
Builtins : : init ( " max " , new BuiltinFunction ( & builtin_max ) ) ;
Builtins : : init ( " sin " , new BuiltinFunction ( & builtin_sin ) ) ;
Builtins : : init ( " cos " , new BuiltinFunction ( & builtin_cos ) ) ;
Builtins : : init ( " asin " , new BuiltinFunction ( & builtin_asin ) ) ;
Builtins : : init ( " acos " , new BuiltinFunction ( & builtin_acos ) ) ;
Builtins : : init ( " tan " , new BuiltinFunction ( & builtin_tan ) ) ;
Builtins : : init ( " atan " , new BuiltinFunction ( & builtin_atan ) ) ;
Builtins : : init ( " atan2 " , new BuiltinFunction ( & builtin_atan2 ) ) ;
Builtins : : init ( " round " , new BuiltinFunction ( & builtin_round ) ) ;
Builtins : : init ( " ceil " , new BuiltinFunction ( & builtin_ceil ) ) ;
Builtins : : init ( " floor " , new BuiltinFunction ( & builtin_floor ) ) ;
Builtins : : init ( " pow " , new BuiltinFunction ( & builtin_pow ) ) ;
Builtins : : init ( " sqrt " , new BuiltinFunction ( & builtin_sqrt ) ) ;
Builtins : : init ( " exp " , new BuiltinFunction ( & builtin_exp ) ) ;
2011-11-12 23:42:27 +04:00
Builtins : : init ( " len " , new BuiltinFunction ( & builtin_length ) ) ;
2011-11-06 21:37:12 +04:00
Builtins : : init ( " log " , new BuiltinFunction ( & builtin_log ) ) ;
Builtins : : init ( " ln " , new BuiltinFunction ( & builtin_ln ) ) ;
Builtins : : init ( " str " , new BuiltinFunction ( & builtin_str ) ) ;
2014-07-13 20:43:44 +04:00
Builtins : : init ( " chr " , new BuiltinFunction ( & builtin_chr ) ) ;
2014-06-24 06:42:11 +04:00
Builtins : : init ( " concat " , new BuiltinFunction ( & builtin_concat ) ) ;
2011-11-06 21:37:12 +04:00
Builtins : : init ( " lookup " , new BuiltinFunction ( & builtin_lookup ) ) ;
2012-02-15 08:04:40 +04:00
Builtins : : init ( " search " , new BuiltinFunction ( & builtin_search ) ) ;
2011-11-06 21:37:12 +04:00
Builtins : : init ( " version " , new BuiltinFunction ( & builtin_version ) ) ;
Builtins : : init ( " version_num " , new BuiltinFunction ( & builtin_version_num ) ) ;
2014-02-17 01:11:26 +04:00
Builtins : : init ( " norm " , new BuiltinFunction ( & builtin_norm ) ) ;
2014-02-17 02:04:48 +04:00
Builtins : : init ( " cross " , new BuiltinFunction ( & builtin_cross ) ) ;
2013-08-18 19:18:43 +04:00
Builtins : : init ( " parent_module " , new BuiltinFunction ( & builtin_parent_module ) ) ;
2009-06-20 23:00:19 +04:00
}