int main(int argc, char **argv) { /* static to prevent longjmp clobber warning */ static FILE *stream = NULL; static unsigned long line_num = 0; static unsigned long failed_cnt = 0; static unsigned long bomb_cnt = 0; static unsigned long success_cnt = 0; static int ret = 0; char buf[BUFSIZ]; FILE *fp_in = NULL; char *endp = NULL; size_t string_length; int argv_idx; int c; char dt_fmt[50]; /* data type format string */ char *buf_p1; char *buf_p; struct bn_tol tol; /* command line parameters */ static unsigned long test_case_line_num = 0; /* static due to longjmp */ static unsigned long function_num = 0; /* static due to longjmp */ struct bu_vls input_file_name = BU_VLS_INIT_ZERO; struct bu_vls output_file_name = BU_VLS_INIT_ZERO; /* function parameter arrays */ int i[50] = {0}; long l[50] = {0}; fastf_t d[50] = {0.0}; unsigned long u[50] = {0}; /* boolean variables */ static int output_file_name_defined = 0; /* static due to longjmp */ static int process_single_test_case = 0; /* static due to longjmp */ static int process_single_function = 0; /* static due to longjmp */ int input_file_name_defined = 0; int valid_function_number = 0; int process_test_case = 0; int early_exit = 0; static int found_eof = 0; /* static due to longjmp */ /* set initial values in tol structure */ tol.magic = BN_TOL_MAGIC; tol.dist = BN_TOL_DIST; tol.dist_sq = tol.dist * tol.dist; tol.perp = 1e-6; tol.para = 1.0 - tol.perp; if (argc < 2) { bu_log("Too few parameters, %d specified, at least 1 required\n", argc - 1); bu_exit(EXIT_FAILURE, USAGE); } while ((c = bu_getopt(argc, argv, "l:f:i:o:")) != -1) { switch (c) { case 'l': /* test case line number */ errno = 0; test_case_line_num = strtoul(bu_optarg, &endp, 10); if (errno) { bu_log("Invalid test case line number '%s' '%s'\n", bu_optarg, strerror(errno)); bu_exit(EXIT_FAILURE, USAGE); } if ((*endp != '\0') || (bu_optarg == endp) || (strchr(bu_optarg, '-') != '\0')) { bu_log("Invalid test case line number '%s'\n", bu_optarg); bu_exit(EXIT_FAILURE, USAGE); } process_single_test_case = 1; break; case 'f': /* function number */ errno = 0; function_num = strtoul(bu_optarg, &endp, 10); if (errno) { bu_log("Invalid function number '%s' '%s'\n", bu_optarg, strerror(errno)); bu_exit(EXIT_FAILURE, USAGE); } if ((*endp != '\0') || (bu_optarg == endp) || (strchr(bu_optarg, '-') != '\0')) { bu_log("Invalid function number '%s'\n", bu_optarg); bu_exit(EXIT_FAILURE, USAGE); } process_single_function = 1; break; case 'i': /* input file name */ string_length = strlen(bu_optarg); if (string_length >= BUFSIZ) { bu_log("Input file name too long, length was %d but must be less than %d\n", string_length, BUFSIZ); bu_exit(EXIT_FAILURE, USAGE); } bu_vls_strcpy(&input_file_name, bu_optarg); input_file_name_defined = 1; break; case 'o': /* output file name */ string_length = strlen(bu_optarg); if (string_length >= BUFSIZ) { bu_log("Output file name too long, length was %d but must be less than %d\n", string_length, BUFSIZ); bu_exit(EXIT_FAILURE, USAGE); } bu_vls_strcpy(&output_file_name, bu_optarg); output_file_name_defined = 1; break; default: bu_log("Invalid option '%c'.\n", c); bu_exit(EXIT_FAILURE, USAGE); break; } } if (process_single_test_case && process_single_function) { bu_log("Can not specify both test case line number and function number.\n"); early_exit = 1; } if (!input_file_name_defined) { bu_log("Input file name is required but was not specified.\n"); early_exit = 1; } if (early_exit) { bu_vls_free(&input_file_name); bu_vls_free(&output_file_name); bu_exit(EXIT_FAILURE, USAGE); } if ((fp_in = fopen(bu_vls_addr(&input_file_name), "r")) == NULL) { bu_log("Cannot open input file (%s)\n", bu_vls_addr(&input_file_name)); bu_vls_free(&input_file_name); bu_vls_free(&output_file_name); return EXIT_FAILURE; } if (output_file_name_defined) { if ((stream = fopen(bu_vls_addr(&output_file_name), "w")) == NULL) { bu_log("Cannot create output file (%s)\n", bu_vls_addr(&output_file_name)); if (fclose(fp_in) != 0) { bu_log("Unable to close input file.\n"); } bu_vls_free(&input_file_name); bu_vls_free(&output_file_name); return EXIT_FAILURE; } } else { stream = stderr; } /* all output after this point is sent to stream */ fprintf(stream, "Command line parameters: bntester "); for (argv_idx = 1 ; argv_idx < argc ; argv_idx++) { fprintf(stream, "%s ", argv[argv_idx]); } fprintf(stream, "\n"); if (process_single_test_case) { fprintf(stream, "Processing only test case on line number: %lu\n", test_case_line_num); } if (process_single_function) { fprintf(stream, "Processing all test cases for function number: %lu\n", function_num); } if (!process_single_test_case && !process_single_function) { fprintf(stream, "Processing all test cases.\n"); } while (!found_eof) { if (line_num == ULONG_MAX) { fprintf(stream, "ERROR: Input data file exceeded max %lu number of lines.\n", ULONG_MAX); if (fclose(fp_in) != 0) { fprintf(stream, "Unable to close input file.\n"); } if (output_file_name_defined) { if (fclose(stream) != 0) { bu_log("Unable to close output file.\n"); } } bu_vls_free(&input_file_name); bu_vls_free(&output_file_name); return EXIT_FAILURE; } line_num++; if (bu_fgets(buf, BUFSIZ, fp_in) == NULL) { if (feof(fp_in)) { found_eof = 1; continue; } if (ferror(fp_in)) { perror("ERROR: Problem reading file, system error message"); if (fclose(fp_in) != 0) { fprintf(stream, "Unable to close input file.\n"); } } else { perror("Oddness reading input file"); } bu_vls_free(&input_file_name); bu_vls_free(&output_file_name); return EXIT_FAILURE; } else { /* Skip input data file lines which start with a '#' character * or a new line character. */ if ((buf[0] != '#') && (buf[0] != '\n')) { buf_p1 = strtok(buf, "\n"); buf_p = strtok(buf_p1, ", "); /* The 1st parameter of the test case is always an unsigned * long int which represents the function number. This logic * validates the test case function number to ensure it is * an unsigned long int. */ valid_function_number = 1; errno = 0; u[0] = strtoul(buf_p, &endp, 10); if (errno) { fprintf(stream, "Read function number failed, line %lu error msg: '%s' string '%s'\n", line_num, strerror(errno), buf_p); valid_function_number = 0; } else if ((*endp != '\0') || (buf_p == endp) || (strchr(buf_p, '-') != '\0')) { fprintf(stream, "Read function number failed, line %lu string '%s'\n", line_num, buf_p); valid_function_number = 0; } /* This logic restricts processing of the test case(s) to * only those specified by the bntester input parameters. */ process_test_case = 0; if (valid_function_number && process_single_test_case && (test_case_line_num == line_num)) { process_test_case = 1; } else if (valid_function_number && process_single_function && (function_num == u[0])) { process_test_case = 1; } else if (valid_function_number && !process_single_test_case && !process_single_function) { process_test_case = 1; } if (process_test_case) { /* Each case within this switch corresponds to each * function to be tested. */ switch (u[0]) { case 1: /* function 'bn_distsq_line3_pt3' */ bu_strlcpy(dt_fmt, "dddddddddd", sizeof(dt_fmt)); /* defines parameter data types */ if (parse_case(buf_p, i, l, d, u, dt_fmt, line_num, stream)) { /* Parse failed, skipping test case */ ret = 1; } else { double result; if (!BU_SETJUMP) { /* try */ result = bn_distsq_line3_pt3(&d[0], &d[3], &d[6]); if (!NEAR_EQUAL(result, d[9], VUNITIZE_TOL)) { ret = 1; failed_cnt++; fprintf(stream, "Failed function %lu test case on line %lu expected = %.15f result = %.15f\n", u[0], line_num, d[9], result); } else { success_cnt++; } } else { /* catch */ BU_UNSETJUMP; ret = 1; bomb_cnt++; fprintf(stream, "Failed function %lu test case on line %lu bu_bomb encountered.\n", u[0], line_num); } BU_UNSETJUMP; } break; case 2: /* function 'bn_2line3_colinear' */ bu_strlcpy(dt_fmt, "ddddddddddddduddddi", sizeof(dt_fmt)); if (parse_case(buf_p, i, l, d, u, dt_fmt, line_num, stream)) { /* Parse failed, skipping test case */ ret = 1; } else { int result; if (!BU_SETJUMP) { /* try */ tol.magic = u[1]; tol.dist = d[13]; tol.dist_sq = d[14]; tol.perp = d[15]; tol.para = d[16]; result = bn_2line3_colinear(&d[0], &d[3], &d[6], &d[9], d[12], &tol); if (result != i[0]) { ret = 1; failed_cnt++; fprintf(stream, "Failed function %lu test case on line %lu expected = %d result = %d\n", u[0], line_num, i[0], result); } else { success_cnt++; } } else { /* catch */ BU_UNSETJUMP; ret = 1; bomb_cnt++; fprintf(stream, "Failed function %lu test case on line %lu bu_bomb encountered.\n", u[0], line_num); } BU_UNSETJUMP; } break; case 3: /* function 'bn_isect_line3_line3' */ bu_strlcpy(dt_fmt, "dddddddddddddduddddi", sizeof(dt_fmt)); if (parse_case(buf_p, i, l, d, u, dt_fmt, line_num, stream)) { /* Parse failed, skipping test case */ ret = 1; } else { int result; fastf_t t_out = 0.0; fastf_t u_out = 0.0; int t_fail = 0; int u_fail = 0; if (!BU_SETJUMP) { /* try */ tol.magic = u[1]; tol.dist = d[14]; tol.dist_sq = d[15]; tol.perp = d[16]; tol.para = d[17]; result = bn_isect_line3_line3(&t_out, &u_out, &d[2], &d[5], &d[8], &d[11], &tol); if (result != i[0]) { ret = 1; failed_cnt++; fprintf(stream, "Failed function %lu test case on line %lu expected = %d result = %d\n", u[0], line_num, i[0], result); } else if (result == 0) { if (!NEAR_EQUAL(t_out, d[0], tol.dist)) { ret = 1; failed_cnt++; fprintf(stream, "Failed function %lu test case on line %lu result = %d expected t = %.15f result t = %.15f\n", u[0], line_num, result, d[0], t_out); } else { success_cnt++; } } else if (result == 1) { t_fail = !NEAR_EQUAL(t_out, d[0], tol.dist); u_fail = !NEAR_EQUAL(u_out, d[1], tol.dist); if (t_fail) { fprintf(stream, "Failed function %lu test case on line %lu result = %d expected t = %.15f result t = %.15f\n", u[0], line_num, result, d[0], t_out); } if (u_fail) { fprintf(stream, "Failed function %lu test case on line %lu result = %d expected u = %.15f result u = %.15f\n", u[0], line_num, result, d[1], u_out); } if (t_fail || u_fail) { ret = 1; failed_cnt++; } else { /* No other output to validate when result matches expected and * result is not 0 and not 1. */ success_cnt++; } } else { success_cnt++; } } else { /* catch */ BU_UNSETJUMP; ret = 1; bomb_cnt++; fprintf(stream, "Failed function %lu test case on line %lu bu_bomb encountered.\n", u[0], line_num); } BU_UNSETJUMP; } break; case 4: /* function 'bn_isect_lseg3_lseg3' */ bu_strlcpy(dt_fmt, "dddddddddddddduddddi", sizeof(dt_fmt)); if (parse_case(buf_p, i, l, d, u, dt_fmt, line_num, stream)) { /* Parse failed, skipping test case */ ret = 1; } else { int result; fastf_t dist[2] = {0.0, 0.0}; int d0_fail = 0; int d1_fail = 0; if (!BU_SETJUMP) { /* try */ tol.magic = u[1]; tol.dist = d[14]; tol.dist_sq = d[15]; tol.perp = d[16]; tol.para = d[17]; result = bn_isect_lseg3_lseg3(&dist[0], &d[2], &d[5], &d[8], &d[11], &tol); if (result != i[0]) { ret = 1; failed_cnt++; fprintf(stream, "Failed function %lu test case on line %lu expected = %d result = %d\n", u[0], line_num, i[0], result); } else if (result == 0 || result == 1) { d0_fail = !NEAR_EQUAL(dist[0], d[0], VUNITIZE_TOL); d1_fail = !NEAR_EQUAL(dist[1], d[1], VUNITIZE_TOL); if (d0_fail) { fprintf(stream, "Failed function %lu test case on line %lu result = %d expected dist[0] = %.15f result dist[0] = %.15f\n", u[0], line_num, result, d[0], dist[0]); } if (d1_fail) { fprintf(stream, "Failed function %lu test case on line %lu result = %d expected dist[1] = %.15f result dist[1] = %.15f\n", u[0], line_num, result, d[1], dist[1]); } if (d0_fail || d1_fail) { ret = 1; failed_cnt++; } else { /* No other output to validate when result matches expected and * result is not 0 and not 1. */ success_cnt++; } } else { success_cnt++; } } else { /* catch */ BU_UNSETJUMP; ret = 1; bomb_cnt++; fprintf(stream, "Failed function %lu test case on line %lu bu_bomb encountered.\n", u[0], line_num); } BU_UNSETJUMP; } break; default: fprintf(stream, "ERROR: Unknown function number %lu test case on line %lu, skipping test case.\n", u[0], line_num); bu_vls_free(&input_file_name); bu_vls_free(&output_file_name); return EXIT_FAILURE; break; } /* End of function number switch */ } } /* End of if statement skipping lines starting with '#' or new line */ } } /* End of while loop reading lines from data file */ fprintf(stream, "Summary: %lu total test cases success.\n", success_cnt); fprintf(stream, "Summary: %lu total test cases failed.\n", failed_cnt); fprintf(stream, "Summary: %lu total test cases bomb.\n", bomb_cnt); if (output_file_name_defined) { bu_log("Summary: %lu total test cases success.\n", success_cnt); bu_log("Summary: %lu total test cases failed.\n", failed_cnt); bu_log("Summary: %lu total test cases bomb.\n", bomb_cnt); } fprintf(stream, "Done.\n"); if (output_file_name_defined) { bu_log("Done.\n"); } if (fclose(fp_in) != 0) { fprintf(stream, "Unable to close input file.\n"); } if (output_file_name_defined) { if (fclose(stream) != 0) { bu_log("Unable to close output file.\n"); } } bu_vls_free(&input_file_name); bu_vls_free(&output_file_name); return ret; }
int bn_math_cmd(ClientData clientData, Tcl_Interp *interp, int argc, char **argv) { void (*math_func)(); struct bu_vls result; math_func = (void (*)())clientData; /* object-to-function cast */ bu_vls_init(&result); if (math_func == bn_mat_mul) { mat_t o, a, b; if (argc < 3 || bn_decode_mat(a, argv[1]) < 16 || bn_decode_mat(b, argv[2]) < 16) { bu_vls_printf(&result, "usage: %s matA matB", argv[0]); goto error; } bn_mat_mul(o, a, b); bn_encode_mat(&result, o); } else if (math_func == bn_mat_inv || math_func == bn_mat_trn) { mat_t o, a; if (argc < 2 || bn_decode_mat(a, argv[1]) < 16) { bu_vls_printf(&result, "usage: %s mat", argv[0]); goto error; } (*math_func)(o, a); bn_encode_mat(&result, o); } else if (math_func == bn_matXvec) { mat_t m; hvect_t i, o; if (argc < 3 || bn_decode_mat(m, argv[1]) < 16 || bn_decode_hvect(i, argv[2]) < 4) { bu_vls_printf(&result, "usage: %s mat hvect", argv[0]); goto error; } bn_matXvec(o, m, i); bn_encode_hvect(&result, o); } else if (math_func == bn_mat4x3pnt) { mat_t m; point_t i, o; if (argc < 3 || bn_decode_mat(m, argv[1]) < 16 || bn_decode_vect(i, argv[2]) < 3) { bu_vls_printf(&result, "usage: %s mat point", argv[0]); goto error; } bn_mat4x3pnt(o, m, i); bn_encode_vect(&result, o); } else if (math_func == bn_mat4x3vec) { mat_t m; vect_t i, o; if (argc < 3 || bn_decode_mat(m, argv[1]) < 16 || bn_decode_vect(i, argv[2]) < 3) { bu_vls_printf(&result, "usage: %s mat vect", argv[0]); goto error; } bn_mat4x3vec(o, m, i); bn_encode_vect(&result, o); } else if (math_func == bn_hdivide) { hvect_t i; vect_t o; if (argc < 2 || bn_decode_hvect(i, argv[1]) < 4) { bu_vls_printf(&result, "usage: %s hvect", argv[0]); goto error; } bn_hdivide(o, i); bn_encode_vect(&result, o); } else if (math_func == bn_vjoin1) { point_t o; point_t b, d; fastf_t c; if (argc < 4) { bu_vls_printf(&result, "usage: %s pnt scale dir", argv[0]); goto error; } if ( bn_decode_vect(b, argv[1]) < 3) goto error; if (Tcl_GetDouble(interp, argv[2], &c) != TCL_OK) goto error; if ( bn_decode_vect(d, argv[3]) < 3) goto error; VJOIN1( o, b, c, d ); /* bn_vjoin1( o, b, c, d ) */ bn_encode_vect(&result, o); } else if ( math_func == bn_vblend) { point_t a, c, e; fastf_t b, d; if ( argc < 5 ) { bu_vls_printf(&result, "usage: %s scale pnt scale pnt", argv[0]); goto error; } if ( Tcl_GetDouble(interp, argv[1], &b) != TCL_OK) goto error; if ( bn_decode_vect( c, argv[2] ) < 3) goto error; if ( Tcl_GetDouble(interp, argv[3], &d) != TCL_OK) goto error; if ( bn_decode_vect( e, argv[4] ) < 3) goto error; VBLEND2( a, b, c, d, e ) bn_encode_vect( &result, a ); } else if (math_func == bn_mat_ae) { mat_t o; double az, el; if (argc < 3) { bu_vls_printf(&result, "usage: %s azimuth elevation", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[1], &az) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[2], &el) != TCL_OK) goto error; bn_mat_ae(o, (fastf_t)az, (fastf_t)el); bn_encode_mat(&result, o); } else if (math_func == bn_ae_vec) { fastf_t az, el; vect_t v; if (argc < 2 || bn_decode_vect(v, argv[1]) < 3) { bu_vls_printf(&result, "usage: %s vect", argv[0]); goto error; } bn_ae_vec(&az, &el, v); bu_vls_printf(&result, "%g %g", az, el); } else if (math_func == bn_aet_vec) { fastf_t az, el, twist, accuracy; vect_t vec_ae, vec_twist; if (argc < 4 || bn_decode_vect(vec_ae, argv[1]) < 3 || bn_decode_vect(vec_twist, argv[2]) < 3 || sscanf(argv[3], "%lf", &accuracy) < 1) { bu_vls_printf(&result, "usage: %s vec_ae vec_twist accuracy", argv[0]); goto error; } bn_aet_vec(&az, &el, &twist, vec_ae, vec_twist, accuracy); bu_vls_printf(&result, "%g %g %g", az, el, twist); } else if (math_func == bn_mat_angles) { mat_t o; double alpha, beta, ggamma; if (argc < 4) { bu_vls_printf(&result, "usage: %s alpha beta gamma", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[1], &alpha) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[2], &beta) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[3], &ggamma) != TCL_OK) goto error; bn_mat_angles(o, alpha, beta, ggamma); bn_encode_mat(&result, o); } else if (math_func == bn_eigen2x2) { fastf_t val1, val2; vect_t vec1, vec2; double a, b, c; if (argc < 4) { bu_vls_printf(&result, "usage: %s a b c", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[1], &a) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[2], &c) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[3], &b) != TCL_OK) goto error; bn_eigen2x2(&val1, &val2, vec1, vec2, (fastf_t)a, (fastf_t)b, (fastf_t)c); bu_vls_printf(&result, "%g %g {%g %g %g} {%g %g %g}", val1, val2, V3ARGS(vec1), V3ARGS(vec2)); } else if (math_func == bn_mat_fromto) { mat_t o; vect_t from, to; if (argc < 3 || bn_decode_vect(from, argv[1]) < 3 || bn_decode_vect(to, argv[2]) < 3) { bu_vls_printf(&result, "usage: %s vecFrom vecTo", argv[0]); goto error; } bn_mat_fromto(o, from, to); bn_encode_mat(&result, o); } else if (math_func == bn_mat_xrot || math_func == bn_mat_yrot || math_func == bn_mat_zrot) { mat_t o; double s, c; if (argc < 3) { bu_vls_printf(&result, "usage: %s sinAngle cosAngle", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[1], &s) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[2], &c) != TCL_OK) goto error; (*math_func)(o, s, c); bn_encode_mat(&result, o); } else if (math_func == bn_mat_lookat) { mat_t o; vect_t dir; int yflip; if (argc < 3 || bn_decode_vect(dir, argv[1]) < 3) { bu_vls_printf(&result, "usage: %s dir yflip", argv[0]); goto error; } if (Tcl_GetBoolean(interp, argv[2], &yflip) != TCL_OK) goto error; bn_mat_lookat(o, dir, yflip); bn_encode_mat(&result, o); } else if (math_func == bn_vec_ortho || math_func == bn_vec_perp) { vect_t ov, vec; if (argc < 2 || bn_decode_vect(vec, argv[1]) < 3) { bu_vls_printf(&result, "usage: %s vec", argv[0]); goto error; } (*math_func)(ov, vec); bn_encode_vect(&result, ov); } else if (math_func == bn_mat_scale_about_pt_wrapper) { mat_t o; vect_t v; double scale; int status; if (argc < 3 || bn_decode_vect(v, argv[1]) < 3) { bu_vls_printf(&result, "usage: %s pt scale", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[2], &scale) != TCL_OK) goto error; bn_mat_scale_about_pt_wrapper(&status, o, v, scale); if (status != 0) { bu_vls_printf(&result, "error performing calculation"); goto error; } bn_encode_mat(&result, o); } else if (math_func == bn_mat_xform_about_pt) { mat_t o, xform; vect_t v; if (argc < 3 || bn_decode_mat(xform, argv[1]) < 16 || bn_decode_vect(v, argv[2]) < 3) { bu_vls_printf(&result, "usage: %s xform pt", argv[0]); goto error; } bn_mat_xform_about_pt(o, xform, v); bn_encode_mat(&result, o); } else if (math_func == bn_mat_arb_rot) { mat_t o; point_t pt; vect_t dir; double angle; if (argc < 4 || bn_decode_vect(pt, argv[1]) < 3 || bn_decode_vect(dir, argv[2]) < 3) { bu_vls_printf(&result, "usage: %s pt dir angle", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[3], &angle) != TCL_OK) return TCL_ERROR; bn_mat_arb_rot(o, pt, dir, (fastf_t)angle); bn_encode_mat(&result, o); } else if (math_func == quat_mat2quat) { mat_t mat; quat_t quat; if (argc < 2 || bn_decode_mat(mat, argv[1]) < 16) { bu_vls_printf(&result, "usage: %s mat", argv[0]); goto error; } quat_mat2quat(quat, mat); bn_encode_quat(&result, quat); } else if (math_func == quat_quat2mat) { mat_t mat; quat_t quat; if (argc < 2 || bn_decode_quat(quat, argv[1]) < 4) { bu_vls_printf(&result, "usage: %s quat", argv[0]); goto error; } quat_quat2mat(mat, quat); bn_encode_mat(&result, mat); } else if (math_func == bn_quat_distance_wrapper) { quat_t q1, q2; double d; if (argc < 3 || bn_decode_quat(q1, argv[1]) < 4 || bn_decode_quat(q2, argv[2]) < 4) { bu_vls_printf(&result, "usage: %s quatA quatB", argv[0]); goto error; } bn_quat_distance_wrapper(&d, q1, q2); bu_vls_printf(&result, "%g", d); } else if (math_func == quat_double || math_func == quat_bisect || math_func == quat_make_nearest) { quat_t oqot, q1, q2; if (argc < 3 || bn_decode_quat(q1, argv[1]) < 4 || bn_decode_quat(q2, argv[2]) < 4) { bu_vls_printf(&result, "usage: %s quatA quatB", argv[0]); goto error; } (*math_func)(oqot, q1, q2); bn_encode_quat(&result, oqot); } else if (math_func == quat_slerp) { quat_t oq, q1, q2; double d; if (argc < 4 || bn_decode_quat(q1, argv[1]) < 4 || bn_decode_quat(q2, argv[2]) < 4) { bu_vls_printf(&result, "usage: %s quat1 quat2 factor", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[3], &d) != TCL_OK) goto error; quat_slerp(oq, q1, q2, d); bn_encode_quat(&result, oq); } else if (math_func == quat_sberp) { quat_t oq, q1, qa, qb, q2; double d; if (argc < 6 || bn_decode_quat(q1, argv[1]) < 4 || bn_decode_quat(qa, argv[2]) < 4 || bn_decode_quat(qb, argv[3]) < 4 || bn_decode_quat(q2, argv[4]) < 4) { bu_vls_printf(&result, "usage: %s quat1 quatA quatB quat2 factor", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[5], &d) != TCL_OK) goto error; quat_sberp(oq, q1, qa, qb, q2, d); bn_encode_quat(&result, oq); } else if (math_func == quat_exp || math_func == quat_log) { quat_t qout, qin; if (argc < 2 || bn_decode_quat(qin, argv[1]) < 4) { bu_vls_printf(&result, "usage: %s quat", argv[0]); goto error; } (*math_func)(qout, qin); bn_encode_quat(&result, qout); } else if (math_func == (void (*)())bn_isect_line3_line3) { double t, u; point_t pt, a; vect_t dir, c; int i; static const struct bn_tol tol = { BN_TOL_MAGIC, 0.005, 0.005*0.005, 1e-6, 1-1e-6 }; if (argc != 5) { bu_vls_printf(&result, "Usage: bn_isect_line3_line3 pt dir pt dir (%d args specified)", argc-1); goto error; } if (bn_decode_vect(pt, argv[1]) < 3) { bu_vls_printf(&result, "bn_isect_line3_line3 no pt: %s\n", argv[0]); goto error; } if (bn_decode_vect(dir, argv[2]) < 3) { bu_vls_printf(&result, "bn_isect_line3_line3 no dir: %s\n", argv[0]); goto error; } if (bn_decode_vect(a, argv[3]) < 3) { bu_vls_printf(&result, "bn_isect_line3_line3 no a pt: %s\n", argv[0]); goto error; } if (bn_decode_vect(c, argv[4]) < 3) { bu_vls_printf(&result, "bn_isect_line3_line3 no c dir: %s\n", argv[0]); goto error; } i = bn_isect_line3_line3(&t, &u, pt, dir, a, c, &tol); if (i != 1) { bu_vls_printf(&result, "bn_isect_line3_line3 no intersection: %s\n", argv[0]); goto error; } VJOIN1(a, pt, t, dir); bn_encode_vect(&result, a); } else if (math_func == (void (*)())bn_isect_line2_line2) { double dist[2]; point_t pt, a; vect_t dir, c; int i; static const struct bn_tol tol = { BN_TOL_MAGIC, 0.005, 0.005*0.005, 1e-6, 1-1e-6 }; if (argc != 5) { bu_vls_printf(&result, "Usage: bn_isect_line2_line2 pt dir pt dir (%d args specified)", argc-1); goto error; } /* i = bn_isect_line2_line2 {0 0} {1 0} {1 1} {0 -1} */ VSETALL(pt, 0.0); VSETALL(dir, 0.0); VSETALL(a, 0.0); VSETALL(c, 0.0); if (bn_decode_vect(pt, argv[1]) < 2) { bu_vls_printf(&result, "bn_isect_line2_line2 no pt: %s\n", argv[0]); goto error; } if (bn_decode_vect(dir, argv[2]) < 2) { bu_vls_printf(&result, "bn_isect_line2_line2 no dir: %s\n", argv[0]); goto error; } if (bn_decode_vect(a, argv[3]) < 2) { bu_vls_printf(&result, "bn_isect_line2_line2 no a pt: %s\n", argv[0]); goto error; } if (bn_decode_vect(c, argv[4]) < 2) { bu_vls_printf(&result, "bn_isect_line2_line2 no c dir: %s\n", argv[0]); goto error; } i = bn_isect_line2_line2(dist, pt, dir, a, c, &tol); if (i != 1) { bu_vls_printf(&result, "bn_isect_line2_line2 no intersection: %s\n", argv[0]); goto error; } VJOIN1(a, pt, dist[0], dir); bu_vls_printf(&result, "%g %g", a[0], a[1]); } else { bu_vls_printf(&result, "libbn/bn_tcl.c: math function %s not supported yet\n", argv[0]); goto error; } Tcl_AppendResult(interp, bu_vls_addr(&result), (char *)NULL); bu_vls_free(&result); return TCL_OK; error: Tcl_AppendResult(interp, bu_vls_addr(&result), (char *)NULL); bu_vls_free(&result); return TCL_ERROR; }