// // Copyright (c) 1993-2022 Robert McNeel & Associates. All rights reserved. // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert // McNeel & Associates. // // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF // MERCHANTABILITY ARE HEREBY DISCLAIMED. // // For complete openNURBS copyright information see . // //////////////////////////////////////////////////////////////// #include "opennurbs.h" #if !defined(ON_COMPILING_OPENNURBS) // This check is included in all opennurbs source .c and .cpp files to insure // ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled. // When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined // and the opennurbs .h files alter what is declared and how it is declared. #error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs #endif int ON_ParsePointExpression( const wchar_t* str, int str_count, ON::AngleUnitSystem default_str_angle_unit_system, ON::LengthUnitSystem point_value_unit_system, ON_3dPoint* point_value ) { ON_ParseSettings ps(ON_ParseSettings::DefaultSettingsInRadians); ps.SetDefaultAngleUnitSystem(default_str_angle_unit_system); return ON_ParsePointExpression( str,str_count, ps, point_value_unit_system,point_value, 0); } int ON_ParsePointExpression( const wchar_t* str, int str_count, ON::AngleUnitSystem default_str_angle_unit_system, const ON_UnitSystem& point_value_unit_system, ON_3dPoint* point_value ) { ON_ParseSettings ps(ON_ParseSettings::DefaultSettingsInRadians); ps.SetDefaultAngleUnitSystem(default_str_angle_unit_system); return ON_ParsePointExpression( str,str_count, ps, point_value_unit_system,point_value, 0); } int ON_ParsePointExpression( const wchar_t* str, int str_count, ON_ParseSettings parse_settings, const ON_UnitSystem& point_value_unit_system, ON_3dPoint* point_value, ON_ParseSettings* parse_results ) { ON::LengthUnitSystem pt_unit_system; double pt_scale = 1.0; switch(point_value_unit_system.UnitSystem()) { case ON::LengthUnitSystem::CustomUnits: pt_unit_system = ON::LengthUnitSystem::Meters; pt_scale = ON::UnitScale(pt_unit_system,point_value_unit_system); break; default: pt_unit_system = point_value_unit_system.UnitSystem(); pt_scale = 1.0; break; } const int str_index = ON_ParsePointExpression( str, str_count, parse_settings, pt_unit_system, point_value, parse_results ); if ( point_value && str_index > 0 && 1.0 != pt_scale ) { if ( ON_IsValid(point_value->x) ) point_value->x *= pt_scale; if ( ON_IsValid(point_value->y) ) point_value->y *= pt_scale; if ( ON_IsValid(point_value->z) ) point_value->z *= pt_scale; } return str_index; } ON_2dVector CosineAndSine(double a) { ON_2dVector v; if ( ON_IsValid(a) ) { v.x = cos(a); v.y = sin(a); if ( fabs(v.x) >= ON_EPSILON || fabs(v.y) <= ON_EPSILON ) { v.x = (v.x < 0.0) ? -1.0 : 1.0; v.y = 0.0; } else if ( fabs(v.y) >= ON_EPSILON || fabs(v.x) <= ON_EPSILON ) { v.y = (v.y < 0.0) ? -1.0 : 1.0; v.x = 0.0; } } else { v = ON_2dVector::NanVector; } return v; } int ON_ParsePointExpression( const wchar_t* str, int str_count, ON_ParseSettings parse_settings, ON::LengthUnitSystem point_value_unit_system, ON_3dPoint* point_value, ON_ParseSettings* parse_results ) { ON_2dVector cos_sin_a0, cos_sin_a1; double x = ON_UNSET_VALUE, y = ON_UNSET_VALUE, z = 0.0; double r = ON_UNSET_VALUE, polar_angle = ON_UNSET_VALUE, spherical_angle = ON_UNSET_VALUE; if ( point_value ) *point_value = ON_3dPoint::Origin; if ( parse_results) *parse_results = ON_ParseSettings::FalseSettings; ON_ParseSettings prx(ON_ParseSettings::FalseSettings); ON_ParseSettings pry(ON_ParseSettings::FalseSettings); ON_ParseSettings prz(ON_ParseSettings::FalseSettings); int str_index = 0; bool bPolarAngle = false; for(;;) { if ( -1 == str_count ) str_count = ON_ParseSettings::max_expression_str_count; if ( str_count <= 0 ) break; int i0 = 0; if ( parse_settings.ParseLeadingWhiteSpace() ) { while ( i0 < str_count && parse_settings.IsLeadingWhiteSpace(str[i0]) ) i0++; if ( i0 >= str_count ) break; parse_settings.SetParseLeadingWhiteSpace(false); } int i1 = ON_ParseLengthExpression( str+i0, str_count-i0, parse_settings, point_value_unit_system, &x, &prx, 0 ); if ( i1 < 1) break; i1 += i0; if ( i1 == str_count && i0+1 == i1 && '0' == str[i0] && 0.0 == x ) { // world origin specified as a single zero. y = 0.0; z = 0.0; str_index = i0+i1; break; } if ( i1 >= str_count ) break; if ( i1+2 <= str_count && str[i1] == ',' && str[i1+1] == '<' ) { // It is a common for people to type "d,= str_count) break; } int i2; if ( str[i1] != ',' ) { i1++; if ( i1 >= str_count ) break; i2 = ON_ParseLengthExpression( str+i1, str_count-i1, parse_settings, point_value_unit_system, &y, &pry, 0 ); if ( i2 > 0 && i1+i0 <= str_count && ON_IsValid(x) && ON_IsValid(y) ) { r = ON_2dVector(x,y).Length(); } } else if ( str[i1] == '<' ) { bPolarAngle = true; r = x; x = ON_UNSET_VALUE; i1++; if ( i1 >= str_count ) break; i2 = ON_ParseAngleExpression( str+i1, str_count-i1, parse_settings, ON::AngleUnitSystem::Radians, &polar_angle, &pry, 0 ); if ( i2 > 0 && i1+i0 <= str_count && ON_IsValid(polar_angle) && ON_IsValid(r) ) { cos_sin_a0 = CosineAndSine(polar_angle); x = r*cos_sin_a0.x; y = r*cos_sin_a0.y; } else { break; } } else if ( i0+1 == i1 && '0' == str[i0] && 0.0 == x ) { // single 0 for origin y = 0.0; str_index = i1; pry = ON_ParseSettings::FalseSettings; break; } else { i2 = 0; } if ( i2 <= 0 ) break; i2 += i1; if ( i2 >= str_count ) { // 2d point str_index = i2; break; } if ( i2+2 <= str_count && str[i2] == ',' && str[i2+1] == '<' ) { // It is a common for people to type "x,y,= str_count ) break; } int i3; if ( str[i2] == ',' ) { i2++; if ( i2 >= str_count ) break; i3 = ON_ParseLengthExpression( str+i2, str_count-i2, parse_settings, point_value_unit_system, &z, &prz, 0 ); } else if ( str[i2] == '<' ) { // spherical angle i3 = ON_ParseAngleExpression( str+i2, str_count-i2, parse_settings, ON::AngleUnitSystem::Radians, &spherical_angle, &prz, 0 ); if ( i3 <= 0 || i2+i3 > str_count ) break; if ( !ON_IsValid(spherical_angle) || !ON_IsValid(r) || !(r >= 0.0) ) break; cos_sin_a1 = CosineAndSine(spherical_angle); if ( bPolarAngle ) { // spherical coordinates (r= 0.0 ) { x = r*cos_sin_a1.x; y = r*cos_sin_a1.x; z = r*cos_sin_a1.y; } else { break; } } else if ( cos_sin_a1.x > 0.0 ) { // elevation (x,y str_count ) break; str_index = i3; break; } if ( str_index > 0 ) { if ( point_value ) { point_value->x = x; point_value->y = y; point_value->z = z; } } else { if ( !prx.ParseError() ) prx = ON_ParseSettings::FalseSettings; if ( !pry.ParseError() ) pry = ON_ParseSettings::FalseSettings; if ( !prz.ParseError() ) prz = ON_ParseSettings::FalseSettings; } if ( parse_results ) { *parse_results = (prx || pry || prz); } return str_index; }