//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // function.cc // // Vincent LE PRINCE // Copyright (C) 2000-2005 Vincent LE PRINCE // This file is part of the TRUEVISION Package // 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. // // 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ //******************************************************************************************* #include "include/function.h" #include #include #include #include #include #include "include/fnintern.h" /* Some files do not define M_PI... */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif const char *TvFuncParserErrors[] = { N_("Expression expected, operator found instead"), N_("Unknown function : "), N_("Unknown keyword : "), N_("Numeric expression expected at end, nothing found"), N_("Wrong number of arguments for function : "), }; const int TvFunc_Constants_num = 7; const char *TvFunc_Constants_str[ TvFunc_Constants_num ] = { "false", "no", "off", "on", "pi", "true", "yes" }; const double TvFunc_Constants_vals[ TvFunc_Constants_num ] = { 0, 0, 0, 1, M_PI, 1, 1 }; const int TvFunc_Var_num = 6; const char *TvFunc_Var_str[ TvFunc_Var_num ] = { "x", "y", "z", "t", "u","v" }; const int TvFunc_Var_vals[ TvFunc_Var_num ] = { 0,1,2,2,0,1 }; const int TvFunc_Func_num = 104; const int First_Internal = 28; const char *TvFunc_Func_str[ TvFunc_Func_num ] = { "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "ceil", "cos", "cosh", "degrees", "exp", "floor", "int", "ln", "log", "radians", "sin", "sinh", "sqrt", "tan", "tanh", "atan2", "div", "mod", "pow", "max", "min", // Pov internal functions "f_algbr_cyl1", "f_algbr_cyl2", "f_algbr_cyl3", "f_algbr_cyl4", "f_bicorn", "f_bifolia", "f_blob", "f_blob2", "f_boy_surface", "f_comma", "f_cross_ellipsoids", "f_crossed_through", "f_cubic_saddle", "f_cushion", "f_devils_curve", "f_devils_curve_2d", "f_dupin_cyclid", "f_ellipsoid", "f_enneper", "f_flange_cover", "f_folium_surface", "f_folium_surface_2d", "f_glob", "f_heart", "f_helical_torus", "f_helix1", "f_helix2", "f_hex_x", "f_hex_y", "f_hetero_mf", "f_hunt_surface", "f_hyperbolic_torus", "f_isect_ellipsoid", "f_kampyle_of_eudoxus", "f_kampyle_of_eudoxus_2d", "f_klein_bottle", "f_kummer_surface_v1", "f_kummer_surface_v2", "f_lemniscate_of_gerono", "f_lemniscate_of_gerono_2d", "f_mesh1", "f_mitre", " f_nodal_cubic", "f_odd", "f_ovals_of_cassini", "f_paraboloid", "f_parabolic_torus", "f_ph", "f_pillow", "f_piriform", "f_piriform_2d", "f_poly4", "f_polytubes", "f_quantum", "f_quartic_paraboloid", "f_quartic_saddle", "f_quartic_cylinder", "f_r", "f_ridge", "f_ridged_mf", "f_rounded_box", "f_sphere", "f_spikes", "f_spikes_2d", "f_spiral", "f_steiners_roman", "f_strophoid", "f_strophoid_2d", "f_superellipsoid", "f_th", "f_torus", "f_torus2", "f_torus_gumdrop", "f_umbrella", "f_witch_of_agnesi", "f_witch_of_agnesi_2d" }; const int TvFunc_Func_args[ TvFunc_Func_num ] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, // Pov internal functions 8, 8, 8, 8, 5, 5, 8, 7, 5, 4, 7, 4, 4, 4, 4, 9, 9, 6, 4, 7, 6, 9, 4, 4, 13, 10, 10, 4, 4, 9, 4, 6, 7, 6, 9, 4, 4, 7, 4, 9, 8, 4, 4, 4, 7, 4, 6, 3, 4, 4, 10, 8, 9, 4, 4, 4, 6, 3, 9, 9, 7, 4, 8, 7, 9, 4, 7, 10, 5, 3, 5, 6, 4, 4, 5, 9 }; //***************************************************************************************** // Function operator object //***************************************************************************************** TvFuncOp::TvFuncOp( char car ) { folded = false; if ( car == '+' ) { type = TV_FUNC_OP_PLUS; return; } if ( car == '-' ) { type = TV_FUNC_OP_MINUS; return; } if ( car == '*' ) { type = TV_FUNC_OP_PROD; return; } if ( car == '/' ) { type = TV_FUNC_OP_DIV; return; } } TvFuncOp::~TvFuncOp() { Exprs.clear(); args.clear(); } double TvFuncOp::evaluate( float x, float y, float z ) { //cout << "\neval type =" << type; if ( type == TV_FUNC_EQUAL ) { //cout << "\neval = " << Exprs[0]->evaluate( x, y, z ); cout.flush(); return Exprs[0]->evaluate( x, y, z ); } double arg1 = args[0]->evaluate( x, y, z ); double arg2 = args[1]->evaluate( x, y, z ); if ( type == TV_FUNC_OP_PLUS ) return arg1+arg2; if ( type == TV_FUNC_OP_MINUS ) return arg1-arg2; if ( type == TV_FUNC_OP_PROD ) return arg1*arg2; if ( type == TV_FUNC_OP_DIV ) { if ( arg2 == 0 ) return 0; else return arg1/arg2; } return 0; } //***************************************************************************************** // Function expression object //***************************************************************************************** TvFuncExpr::TvFuncExpr( char *str, int len ) { string = str; string_len = len; status = true; error_code = -1; error_str_len = -1; error_str_tmp = NULL; invert = false; negate = false; //cout << "\ngot expr ->"; //for ( int i = 0 ; i < len ; i ++ ) cout << str[i]; //cout << "<-"; // Count operators bool op_status = false; vector ops; int brace_count = 0; bool brace_status = false; int par_count = 0; for ( int i = 0 ; i < string_len ; i++ ) { if ( string[i] == '{' ) par_count++; if ( string[i] == '}' ) par_count--; if ( par_count != 0 ) continue; if ( string[i] == '(' && brace_status ) brace_count++; if ( string[i] == ')' ) brace_count--; if ( brace_count != 0 ) continue; if ( string[i] == ' ' || string[i] == '\t' || string[i] == '\n' ) continue; if ( string[i] == '*' ) if (op_status == false ) { status = false; error_code = 0; break; } else { ops.push_back( i ); op_status = false; continue; } if ( string[i]== '/' ) if (op_status == false ) { status = false; error_code = 0; break; } else { ops.push_back( i ); op_status = false; continue; } if ( string[i]== '+' ) if (op_status == true ) { ops.push_back( i ); op_status = false; continue; } if ( string[i]== '-' ) if (op_status == true ) { ops.push_back( i ); op_status = false; continue; } op_status = true; brace_status = true; } if ( status == false ) return; // Parsing modes if ( ops.size() == 0 ) { // mode 1 : function, constants, variables... mode = 1; parse_expression(); } else { // mode 2 : arythmetic expressions mode = 2; int offset = 0; for ( unsigned int i = 0; i < ops.size() ; i++ ) { TvFuncOp * eq = new TvFuncOp( TV_FUNC_EQUAL ); TvFuncExpr *expr = new TvFuncExpr( string+offset, ops[i] - offset ); if ( expr->get_status() == false ) { propagate_error( expr ); return; } eq->add_expr( expr ); AryTree.push_back( eq ); offset = ops[i]+1; TvFuncOp * op = new TvFuncOp( string[ ops[i] ] ); AryTree.push_back( op ); } TvFuncOp * eq = new TvFuncOp( TV_FUNC_EQUAL ); TvFuncExpr *expr = new TvFuncExpr( string+offset, string_len-offset ); if ( expr->get_status() == false ) { propagate_error( expr ); return; } eq->add_expr( expr ); AryTree.push_back( eq ); compile_ary_tree(); } ops.clear(); } TvFuncExpr::~TvFuncExpr() { if ( error_str_tmp != NULL ) delete error_str_tmp; function_args.clear(); AryTree.clear(); } void TvFuncExpr::parse_expression() { int i = 0; // skip spaces, braces and tabs, setting invert mode while ( i < string_len ) { if ( string[i] == ' ' || string[i] == '\t' || string[i] == '\n' || string[i] == '(' ) { i++; continue; } if ( string[i] == '-' ) { i++; invert = !invert; continue; } if ( string[i] == '!' ) { i++; negate = !negate; continue; } if ( string[i] == '+' ) { i++; continue; } break; } // Null expression if ( i == string_len ) { status = false; error_code = 3; return; } // Check for functions bool is_func = false; int brace_offset = 0; for ( brace_offset = i ; brace_offset < string_len ; brace_offset++ ) if ( string[ brace_offset ] == '(' ) { is_func = true; break; } // Functions if ( is_func ) { eval_mode = 1; for ( int f = 0 ; f < TvFunc_Func_num ; f++ ) { int len = strlen( TvFunc_Func_str[f] ); if ( ! strncmp( string+i, TvFunc_Func_str[f], len ) ) { // for extra chars after keyword bool wrong = false; for ( int ump = i + len; ump < brace_offset ; ump++ ) { if ( string[ump] != '(' && string[ump] != ' ' ) { wrong = true; break; } } if ( wrong == true ) continue; function = f; //cout << "\nWe got a func !! -> " << TvFunc_Func_str[function] ; // Get arguments int offset = brace_offset; bool terminate = false; int brace_count = 0; for ( int u = offset+1 ; u < string_len ; u++ ) { if ( string[u] == '(') brace_count++; if ( string[u] == ')') { if ( brace_count == 0 ) terminate = true; else brace_count--; } if ( ( string[u] == ',' && brace_count == 0 ) || terminate == true ) { TvFuncExpr *expr = new TvFuncExpr( string+offset+1, u-offset-1 ); if ( expr->get_status() == false ) { propagate_error( expr ); return; } function_args.push_back( expr ); offset = u; } if ( terminate ) break; } if ( function_args.size() != (unsigned int )TvFunc_Func_args[function] && TvFunc_Func_args[function] != 0 ) { status = false; error_code = 4; error_str = string+i; error_str_len = len; } return; } } // unknown function !! status = false; error_code = 1; error_str = string+i; error_str_len = brace_offset - i; return; } // Pigment block if ( ! strncmp( string+i, "pigment", 7 ) ) { eval_mode = 4; //cout << "\nWe got a pig !! -> "; cout.flush(); return; } // Numeric constant if ( string[i] >= '0' && string[i] <= '9' ) { eval_mode = 2; float temp_const; sscanf( string+i, "%f ", &temp_const ); constant = temp_const; if ( invert ) constant = - constant; if ( negate ) constant = ! constant; //cout << "\nWe got a num const !! -> " << constant; return; } // Symbolic constant for ( int u = 0 ; u < TvFunc_Constants_num ; u++ ) { int len = strlen( TvFunc_Constants_str[u] ); if ( len + i < string_len-1 & string[i+len] != ' ' ) continue; if ( ! strncmp( string+i, TvFunc_Constants_str[u], len ) ) { eval_mode = 2; constant = TvFunc_Constants_vals[u]; if ( invert ) constant = - constant; if ( negate ) constant = ! constant; //cout << "\nWe got a symb const !! -> " << constant; return; } } // Variable for ( int u = 0 ; u < TvFunc_Var_num ; u++ ) { int len = strlen( TvFunc_Var_str[u] ); if ( len + i < string_len-1 & string[i+len] != ' ' ) continue; if ( ! strncmp( string+i, TvFunc_Var_str[u], len ) ) { eval_mode = 3; variable = TvFunc_Var_vals[u]; //cout << "\nWe got a var !! -> " << variable; cout.flush(); return; } } // Unknown status = false; error_code = 2; error_str = string+i; error_str_len = string_len-i; } void TvFuncExpr::compile_ary_tree() { //cout << "\ncompiling tree"; cout.flush(); //cout << "\n\ttree size = " << AryTree.size(); cout.flush(); bool passed = false; while ( !passed ) { passed = true; for ( unsigned int i = 0 ; i < AryTree.size(); i++ ) { if ( ( AryTree[i]->get_type() == TV_FUNC_OP_PROD || AryTree[i]->get_type() == TV_FUNC_OP_DIV ) && ! AryTree[i]->get_folded() ) { //cout << "\none iteration"; AryTree[i]->add_arg( AryTree[i-1] ); AryTree[i]->add_arg( AryTree[i+1] ); AryTree[i]->set_folded(); //cout << "\ntree size = " << AryTree.size(); cout.flush(); AryTree.erase( AryTree.begin() + i +1 ); AryTree.erase( AryTree.begin() + i -1 ); passed = false; break; } } } //cout << "\nfolded"; cout.flush(); //cout << "\ntree size = " << AryTree.size(); cout.flush(); while ( AryTree.size() != 1 ) { //cout << "\ntree size = " << AryTree.size(); cout.flush(); for ( unsigned int i = 0 ; i < AryTree.size(); i++ ) { if ( ( AryTree[i]->get_type() == TV_FUNC_OP_PLUS || AryTree[i]->get_type() == TV_FUNC_OP_MINUS ) && ! AryTree[i]->get_folded() ) { //cout << "\none iteration at i=" << i ; AryTree[i]->add_arg( AryTree[i-1] ); AryTree[i]->add_arg( AryTree[i+1] ); AryTree[i]->set_folded(); AryTree.erase( AryTree.begin() + i +1 ); AryTree.erase( AryTree.begin() + i -1 ); break; } } } //cout << "\ncompiled"; cout.flush(); //cout << "\ntree size = " << AryTree.size(); cout.flush(); } double TvFuncExpr::evaluate( float x, float y, float z ) { if ( mode == 1 ) { // Eval single expression //cout << "\neval exp"; cout.flush(); switch ( eval_mode ) { // Function case 1: { //cout << "\neval function"; cout.flush(); int anum = function_args.size(); double *fargs = new double[ anum ]; for ( int a = 0 ; a < anum ; a++ ) { fargs[a] = function_args[a]->evaluate( x, y, z ); } double res = 0; if ( function == 0 ) res = fabs( fargs[0] ); if ( function == 1 ) res = acos( fargs[0] ); if ( function == 2 ) res = acosh( fargs[0] ); if ( function == 3 ) res = asin( fargs[0] ); if ( function == 4 ) res = asinh( fargs[0] ); if ( function == 5 ) res = atan( fargs[0] ); if ( function == 6 ) res = atanh( fargs[0] ); if ( function == 7 ) res = ceil( fargs[0] ); if ( function == 8 ) res = cos( fargs[0] ); if ( function == 9 ) res = cosh( fargs[0] ); if ( function == 10 ) res = fargs[0] *180.0 / M_PI; if ( function == 11 ) res = exp( fargs[0] ); if ( function == 12 ) res = floor( fargs[0] ); if ( function == 13 ) res = (int)( fargs[0] ); if ( function == 14 ) { if ( fargs[0] != 0 ) res = log( fargs[0] ); else res = 0; } if ( function == 15 ) { if ( fargs[0] != 0 ) res = log10( fargs[0] ); else res = 0; } if ( function == 16 ) res = fargs[0] * M_PI / 180.0; if ( function == 17 ) res = sin( fargs[0] ); if ( function == 18 ) res = sinh( fargs[0] ); if ( function == 19 ) res = sqrt( fargs[0] ); if ( function == 20 ) res = tan( fargs[0] ); if ( function == 21 ) res = tanh( fargs[0] ); if ( function == 22 ) res = atan2( fargs[0], fargs[1] ); if ( function == 23 ) res = (int)fargs[0] / (int)fargs[1]; if ( function == 24 ) res = fmod( fargs[0], fargs[1] ); if ( function == 25 ) res = pow( fargs[0], fargs[1] ); if ( function == 26 ) { res = fargs[0]; for ( int it = 0 ; it < anum ; it++ ) res = res < fargs[it] ? fargs[it] : res; } if ( function == 27 ) { res = fargs[0]; for ( int it = 0 ; it < anum ; it++ ) res = res > fargs[it] ? fargs[it] : res; } if ( function == 28 ) { res = f_algbr_cyl1( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7] );} if ( function == 29 ) { res = f_algbr_cyl2( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7] );} if ( function == 30 ) { res = f_algbr_cyl3( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7] );} if ( function == 31 ) { res = f_algbr_cyl4( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7] );} if ( function == 32 ) { res = f_bicorn( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4] );} if ( function == 33 ) { res = f_bifolia( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4] );} if ( function == 34 ) { res = f_blob( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7] );} if ( function == 35 ) { res = f_blob2( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6] );} if ( function == 36 ) { res = f_boy_surface( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4] ); } if ( function == 37 ) { res = f_comma( fargs[0], fargs[1], fargs[2], fargs[3] ); } if ( function == 38 ) { res = f_cross_ellipsoids( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6] );} if ( function == 39 ) { res = f_crossed_through( fargs[0], fargs[1], fargs[2], fargs[3] ); } if ( function == 40 ) { res = f_cubic_saddle( fargs[0], fargs[1], fargs[2], fargs[3] ); } if ( function == 41 ) { res = f_cushion( fargs[0], fargs[1], fargs[2], fargs[3] ); } if ( function == 42 ) { res = f_devils_curve( fargs[0], fargs[1], fargs[2], fargs[3] ); } if ( function == 43 ) { res = f_devils_curve_2d( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] );} if ( function == 44 ) { res = f_dupin_cyclid( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] );} if ( function == 45 ) { res = f_ellipsoid( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5] );} if ( function == 46 ) { res = f_enneper( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 47 ) { res = f_flange_cover( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6] );} if ( function == 48 ) { res = f_folium_surface( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5] );} if ( function == 49 ) { res = f_folium_surface_2d( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] );} if ( function == 50 ) { res = f_glob( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 51 ) { res = f_heart( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 52 ) { res = f_helical_torus( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] , fargs[9], fargs[10], fargs[11], fargs[12] );} if ( function == 53 ) { res = f_helix1( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] , fargs[9] );} if ( function == 54 ) { res = f_helix2( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] , fargs[9] );} if ( function == 55 ) { res = f_hex_x( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 56 ) { res = f_hex_y( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 57 ) { res = f_hetero_mf( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] );} if ( function == 58 ) { res = f_hunt_surface( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 59 ) { res = f_hyperbolic_torus( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5] );} if ( function == 60 ) { res = f_isect_ellipsoids( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6] );} if ( function == 61 ) { res = f_kampyle_of_eudoxus( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5] );} if ( function == 62 ) { res = f_kampyle_of_eudoxus_2d( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] );} if ( function == 63 ) { res = f_klein_bottle( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 64 ) { res = f_kummer_surface_v1( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 65 ) { res = f_kummer_surface_v2( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6] ); } if ( function == 66 ) { res = f_lemniscate_of_gerono( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 67 ) { res = f_lemniscate_of_gerono_2d( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] );} if ( function == 68 ) { res = f_mesh1( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7] );} if ( function == 69 ) { res = f_mitre( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 70 ) { res = f_nodal_cubic( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 71 ) { res = f_odd( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 72 ) { res = f_ovals_of_cassini( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6] );} if ( function == 73 ) { res = f_paraboloid( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 74 ) { res = f_parabolic_torus( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5] );} if ( function == 75 ) { res = f_ph( fargs[0], fargs[1], fargs[2] );} if ( function == 76 ) { res = f_pillow( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 77 ) { res = f_piriform( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 78 ) { res = f_piriform_2d( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] , fargs[9] );} if ( function == 79 ) { res = f_poly4( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7] );} if ( function == 80 ) { res = f_polytubes( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] );} if ( function == 81 ) { res = f_quantum( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 82 ) { res = f_quartic_paraboloid( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 83 ) { res = f_quartic_saddle( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 84 ) { res = f_quartic_cylinder( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5] );} if ( function == 85 ) { res = f_r( fargs[0], fargs[1], fargs[2] );} if ( function == 86 ) { res = f_ridge( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] );} if ( function == 87 ) { res = f_ridged_mf( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] );} if ( function == 88 ) { res = f_rounded_box( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6] );} if ( function == 89 ) { res = f_sphere( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 90 ) { res = f_spikes( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7] );} if ( function == 91 ) { res = f_spikes_2d( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6] );} if ( function == 92 ) { res = f_spiral( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] );} if ( function == 93 ) { res = f_steiners_roman( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 94 ) { res = f_strophoid( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6] );} if ( function == 95 ) { res = f_strophoid_2d( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] , fargs[9] );} if ( function == 96 ) { res = f_superellipsoid( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4] );} if ( function == 97 ) { res = f_th( fargs[0], fargs[1], fargs[2] );} if ( function == 98 ) { res = f_torus( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4] );} if ( function == 99 ) { res = f_torus2( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5] );} if ( function == 100 ) { res = f_torus_gumdrop( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 101 ) { res = f_umbrella( fargs[0], fargs[1], fargs[2], fargs[3] );} if ( function == 102 ) { res = f_witch_of_agnesi( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4] );} if ( function == 103 ) { res = f_witch_of_agnesi_2d( fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8] );} delete fargs; if ( invert ) res = -res; if ( negate ) res = ! res; return res; } break; // Constant case 2: //cout << "\neval const"; cout.flush(); return constant; break; // Variable case 3: { //cout << "\neval var"; cout.flush(); double vars[3] = { x, y, z }; double res = vars[ TvFunc_Var_vals[variable] ]; if ( invert ) res = -res; if ( negate ) res = ! res; return res; } break; // Pigment block default: case 4: return 0; break; } } else { // eval arythmetic tree //cout << "\nEvaluate tree"; cout.flush(); //cout << "\nsize tree = " << AryTree.size(); cout.flush(); return AryTree[0]->evaluate( x, y, z ); //cout << "\nEvaluate tree"; cout.flush(); } return 0; } char *TvFuncExpr::get_error() { if ( error_code == -1 ) return NULL; if ( error_str_len == -1 ) return (char*)(TvFuncParserErrors[error_code]); int len = strlen( TvFuncParserErrors[error_code] ) + error_str_len + 1; error_str_tmp = new char[ len ]; strcpy( error_str_tmp, TvFuncParserErrors[error_code] ); strncat( error_str_tmp, error_str, error_str_len ); return error_str_tmp; } //***************************************************************************************** // Function object //***************************************************************************************** TvFunction::TvFunction() { string = NULL; expression = NULL; } TvFunction::~TvFunction() { if ( string != NULL ) delete string; if ( expression != NULL ) delete expression; } void TvFunction::set_expression( char *str ) { if ( string != NULL ) delete string; int len = strlen( str ) + 1; string = new char[ len ]; strcpy( string, str ); if ( expression != NULL ) delete expression; expression = new TvFuncExpr( string, len-1 ); } double TvFunction::evaluate( float x, float y, float z ) { return expression->evaluate( x, y, z ); } void TvFunction::define_internals( ofstream & file ) { for ( int i = First_Internal ; i < TvFunc_Func_num ; i++ ) if ( TvFunc_Func_str[i] != NULL && string != NULL ) if ( strstr( string, TvFunc_Func_str[i] ) ) file << "\n#declare " << TvFunc_Func_str[i] << " = function { internal(" << (i-First_Internal) << ") }"; }