/* * Validate points data file unit string and output conversion factor * to millimeters. If string is not a standard units identifier, the * function assumes a custom conversion factor was specified. A valid * null terminated string is expected as input. The function returns * GED_ERROR if the unit string is invalid or if null pointers were * passed to the function. */ int str2mm(const char *units_string, double *conv_factor, struct bu_vls *ged_result_str) { struct bu_vls str = BU_VLS_INIT_ZERO; double tmp_value = 0.0; char *endp = (char *)NULL; int ret = GED_OK; if ((units_string == (char *)NULL) || (conv_factor == (double *)NULL)) { bu_vls_printf(ged_result_str, "NULL pointer(s) passed to function 'str2mm'.\n"); ret = GED_ERROR; } else { bu_vls_strcat(&str, units_string); bu_vls_trimspace(&str); tmp_value = strtod(bu_vls_addr(&str), &endp); if ((endp != bu_vls_addr(&str)) && (*endp == '\0')) { /* convert to double success */ *conv_factor = tmp_value; } else if ((tmp_value = bu_mm_value(bu_vls_addr(&str))) > 0.0) { *conv_factor = tmp_value; } else { bu_vls_printf(ged_result_str, "Invalid units string '%s'\n", units_string); ret = GED_ERROR; } } bu_vls_free(&str); return ret; }
/* * Go poke the rgb values of a region, on the fly. * This does not update the inmemory database, * so any changes will vanish on next re-prep unless other measures * are taken. */ int sh_directchange_shader(ClientData UNUSED(clientData), Tcl_Interp *interp, int argc, const char *argv[]) { long int rtip_val; struct rt_i *rtip; struct region *regp; struct directory *dp; struct bu_vls shader = BU_VLS_INIT_ZERO; if ( argc < 4 ) { Tcl_AppendResult(interp, "Usage: sh_directchange_shader $rtip comb shader_arg(s)\n", NULL); return TCL_ERROR; } rtip_val = atol(argv[1]); rtip = (struct rt_i *)rtip_val; RT_CK_RTI(rtip); if ( rtip->needprep ) { Tcl_AppendResult(interp, "rt_prep() hasn't been called yet, error.\n", NULL); return TCL_ERROR; } if ( (dp = db_lookup( rtip->rti_dbip, argv[2], LOOKUP_NOISY)) == RT_DIR_NULL ) { Tcl_AppendResult(interp, argv[2], ": not found\n", NULL); return TCL_ERROR; } bu_vls_from_argv(&shader, argc-3, argv+3); bu_vls_trimspace(&shader); /* Find all region names which match /comb/ pattern */ for ( BU_LIST_FOR( regp, region, &rtip->HeadRegion ) ) { /* if ( dp->d_flags & RT_DIR_REGION ) { */ /* name will occur at end of region string w/leading slash */ /* } else { */ /* name will occur anywhere, bracketed by slashes */ /* } */ /* XXX quick hack */ if ( strstr( regp->reg_name, argv[2] ) == NULL ) continue; /* Modify the region's shader string */ bu_log("sh_directchange_shader() changing %s\n", regp->reg_name); if ( regp->reg_mater.ma_shader ) bu_free( (void *)regp->reg_mater.ma_shader, "reg_mater.ma_shader"); regp->reg_mater.ma_shader = bu_vls_strdup(&shader); /* Update the shader */ mlib_free(regp); if ( mlib_setup( &mfHead, regp, rtip ) != 1 ) { Tcl_AppendResult(interp, regp->reg_name, ": mlib_setup() failure\n", NULL); } } bu_vls_free(&shader); return TCL_OK; }
/* * Validate 'point file data format string', determine and output the * point-cloud type. A valid null terminated string is expected as * input. The function returns GED_ERROR if the format string is * invalid or if null pointers were passed to the function. */ int str2type(const char *format_string, rt_pnt_type *pnt_type, struct bu_vls *ged_result_str) { struct bu_vls str = BU_VLS_INIT_ZERO; char *temp_string = (char *)NULL; size_t idx = 0; size_t format_string_length = 0; int ret = GED_OK; if ((format_string == (char *)NULL) || (pnt_type == (rt_pnt_type *)NULL)) { bu_vls_printf(ged_result_str, "NULL pointer(s) passed to function 'str2type'.\n"); ret = GED_ERROR; } else { format_string_length = strlen(format_string); /* remove any '?' from format string before testing for point-cloud type */ for (idx = 0 ; idx < format_string_length ; idx++) { if (format_string[idx] != '?') { bu_vls_putc(&str, format_string[idx]); } } bu_vls_trimspace(&str); temp_string = bu_vls_addr(&str); bu_sort(temp_string, strlen(temp_string), sizeof(char), (int (*)(const void *a, const void *b, void *arg))compare_char, NULL); if (BU_STR_EQUAL(temp_string, "xyz")) { *pnt_type = RT_PNT_TYPE_PNT; } else if (BU_STR_EQUAL(temp_string, "bgrxyz")) { *pnt_type = RT_PNT_TYPE_COL; } else if (BU_STR_EQUAL(temp_string, "sxyz")) { *pnt_type = RT_PNT_TYPE_SCA; } else if (BU_STR_EQUAL(temp_string, "ijkxyz")) { *pnt_type = RT_PNT_TYPE_NRM; } else if (BU_STR_EQUAL(temp_string, "bgrsxyz")) { *pnt_type = RT_PNT_TYPE_COL_SCA; } else if (BU_STR_EQUAL(temp_string, "bgijkrxyz")) { *pnt_type = RT_PNT_TYPE_COL_NRM; } else if (BU_STR_EQUAL(temp_string, "ijksxyz")) { *pnt_type = RT_PNT_TYPE_SCA_NRM; } else if (BU_STR_EQUAL(temp_string, "bgijkrsxyz")) { *pnt_type = RT_PNT_TYPE_COL_SCA_NRM; } else { bu_vls_printf(ged_result_str, "Invalid format string '%s'", format_string); ret = GED_ERROR; } } bu_vls_free(&str); return ret; }
/* * 'make_pnts' command for importing point-cloud data into a 'pnts' * primitive. * * Input values: * argv[1] object name * argv[2] filename with path * argv[3] point data file format string * argv[4] point data file units string or conversion factor to millimeters * argv[5] default size of each point * */ int ged_make_pnts(struct ged *gedp, int argc, const char *argv[]) { struct directory *dp; struct rt_db_internal internal; rt_pnt_type type; double local2base; unsigned long numPoints = 0; struct rt_pnts_internal *pnts; double defaultSize = 0.0; void *headPoint = NULL; FILE *fp; int temp_string_index = 0; /* index into temp_string, set to first character in temp_string, i.e. the start */ unsigned long int num_doubles_read = 0; /* counters of double read from file */ int current_character_double = 0; /* flag indicating if current character read is part of a double or delimiter */ int previous_character_double = 0; /* flag indicating if previously read character was part of a double or delimiter */ unsigned long int num_characters_read_from_file = 0; /* counter of number of characters read from file */ unsigned long int start_offset_of_current_double = 0; /* character offset from start of file for current double */ int found_double = 0; /* flag indicating if double encountered in file and needs to be processed */ int found_eof = 0; /* flag indicating if end-of-file encountered when reading file */ int done_processing_format_string = 0; /* flag indicating if loop processing format string should be exited */ char *temp_char_ptr = (char *)NULL; int buf = 0; /* raw character read from file */ double temp_double = 0.0; char temp_string[1024]; int temp_string_size = 1024; /* number of characters that can be stored in temp_string including null terminator character */ /* it is expected that the character representation of a double will never exceed this size string */ char *endp = (char *)NULL; struct bu_vls format_string = BU_VLS_INIT_ZERO; size_t format_string_index = 0; unsigned int num_doubles_per_point = 0; void *point = NULL; char **prompt; static const char *usage = "point_cloud_name filename_with_path file_format file_data_units default_point_size"; prompt = &p_make_pnts[0]; GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR); GED_CHECK_READ_ONLY(gedp, GED_ERROR); GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR); /* initialize result */ bu_vls_trunc(gedp->ged_result_str, 0); if (argc > 6) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } /* prompt for point-cloud name */ if (argc < 2) { bu_vls_printf(gedp->ged_result_str, "%s", prompt[0]); return GED_MORE; } GED_CHECK_EXISTS(gedp, argv[1], LOOKUP_QUIET, GED_ERROR); /* prompt for data file name with path */ if (argc < 3) { bu_vls_printf(gedp->ged_result_str, "%s", prompt[1]); return GED_MORE; } /* prompt for data file format */ if (argc < 4) { bu_vls_printf(gedp->ged_result_str, "%s", prompt[2]); return GED_MORE; } /* Validate 'point file data format string' and return point-cloud type. */ if (str2type(argv[3], &type, gedp->ged_result_str) == GED_ERROR) { return GED_ERROR; } /* prompt for data file units */ if (argc < 5) { bu_vls_printf(gedp->ged_result_str, "%s", prompt[3]); return GED_MORE; } /* Validate the unit string and return conversion factor to millimeters. */ if (str2mm(argv[4], &local2base, gedp->ged_result_str) == GED_ERROR) { return GED_ERROR; } /* prompt for default point size */ if (argc < 6) { bu_vls_printf(gedp->ged_result_str, "%s", prompt[4]); return GED_MORE; } defaultSize = strtod(argv[5], &endp); if ((endp != argv[5]) && (*endp == '\0')) { /* convert to double success */ if (defaultSize < 0.0) { bu_vls_printf(gedp->ged_result_str, "Default point size '%lf' must be non-negative.\n", defaultSize); return GED_ERROR; } } else { bu_vls_printf(gedp->ged_result_str, "Invalid default point size '%s'\n", argv[5]); return GED_ERROR; } bu_vls_strcat(&format_string, argv[3]); bu_vls_trimspace(&format_string); /* init database structure */ RT_DB_INTERNAL_INIT(&internal); internal.idb_major_type = DB5_MAJORTYPE_BRLCAD; internal.idb_type = ID_PNTS; internal.idb_meth = &OBJ[ID_PNTS]; BU_ALLOC(internal.idb_ptr, struct rt_pnts_internal); /* init internal structure */ pnts = (struct rt_pnts_internal *) internal.idb_ptr; pnts->magic = RT_PNTS_INTERNAL_MAGIC; pnts->scale = defaultSize; pnts->type = type; pnts->count = numPoints; /* set again later */ pnts->point = NULL; /* empty list head */ switch (type) { case RT_PNT_TYPE_PNT: BU_ALLOC(headPoint, struct pnt); BU_LIST_INIT(&(((struct pnt *)headPoint)->l)); num_doubles_per_point = 3; break; case RT_PNT_TYPE_COL: BU_ALLOC(headPoint, struct pnt_color); BU_LIST_INIT(&(((struct pnt_color *)headPoint)->l)); num_doubles_per_point = 6; break; case RT_PNT_TYPE_SCA: BU_ALLOC(headPoint, struct pnt_scale); BU_LIST_INIT(&(((struct pnt_scale *)headPoint)->l)); num_doubles_per_point = 4; break; case RT_PNT_TYPE_NRM: BU_ALLOC(headPoint, struct pnt_normal); BU_LIST_INIT(&(((struct pnt_normal *)headPoint)->l)); num_doubles_per_point = 6; break; case RT_PNT_TYPE_COL_SCA: BU_ALLOC(headPoint, struct pnt_color_scale); BU_LIST_INIT(&(((struct pnt_color_scale *)headPoint)->l)); num_doubles_per_point = 7; break; case RT_PNT_TYPE_COL_NRM: BU_ALLOC(headPoint, struct pnt_color_normal); BU_LIST_INIT(&(((struct pnt_color_normal *)headPoint)->l)); num_doubles_per_point = 9; break; case RT_PNT_TYPE_SCA_NRM: BU_ALLOC(headPoint, struct pnt_scale_normal); BU_LIST_INIT(&(((struct pnt_scale_normal *)headPoint)->l)); num_doubles_per_point = 7; break; case RT_PNT_TYPE_COL_SCA_NRM: BU_ALLOC(headPoint, struct pnt_color_scale_normal); BU_LIST_INIT(&(((struct pnt_color_scale_normal *)headPoint)->l)); num_doubles_per_point = 10; break; } BU_ASSERT_PTR(headPoint, !=, NULL); pnts->point = headPoint; if ((fp=fopen(argv[2], "rb")) == NULL) { bu_vls_printf(gedp->ged_result_str, "Make '%s' failed. ", argv[1]); bu_vls_printf(gedp->ged_result_str, "Could not open file '%s'.\n", argv[2]); bu_vls_free(&format_string); rt_db_free_internal(&internal); return GED_ERROR; } while (!found_eof) { /* points_loop */ /* allocate memory for single point structure for current point-cloud type */ switch (type) { case RT_PNT_TYPE_PNT: BU_ALLOC(point, struct pnt); break; case RT_PNT_TYPE_COL: BU_ALLOC(point, struct pnt_color); break; case RT_PNT_TYPE_SCA: BU_ALLOC(point, struct pnt_scale); break; case RT_PNT_TYPE_NRM: BU_ALLOC(point, struct pnt_normal); break; case RT_PNT_TYPE_COL_SCA: BU_ALLOC(point, struct pnt_color_scale); break; case RT_PNT_TYPE_COL_NRM: BU_ALLOC(point, struct pnt_color_normal); break; case RT_PNT_TYPE_SCA_NRM: BU_ALLOC(point, struct pnt_scale_normal); break; case RT_PNT_TYPE_COL_SCA_NRM: BU_ALLOC(point, struct pnt_color_scale_normal); break; } /* make sure we have something */ BU_ASSERT_PTR(point, !=, NULL); while (!found_eof && !done_processing_format_string) { /* format_string_loop */ char format = '\0'; while (!found_eof && !found_double) { /* find_doubles_loop */ format = bu_vls_addr(&format_string)[format_string_index]; buf = fgetc(fp); num_characters_read_from_file++; if (feof(fp)) { if (ferror(fp)) { perror("ERROR: Problem reading file, system error message"); fclose(fp); bu_vls_printf(gedp->ged_result_str, "Make '%s' failed. ", argv[1]); bu_vls_printf(gedp->ged_result_str, "Unable to read file at byte '%lu'.\n", num_characters_read_from_file); bu_vls_free(&format_string); rt_db_free_internal(&internal); return GED_ERROR; } else { found_eof = 1; } } if (found_eof) { fclose(fp); current_character_double = 0; if (num_doubles_read == 0) { bu_vls_printf(gedp->ged_result_str, "Make '%s' failed. ", argv[1]); bu_vls_printf(gedp->ged_result_str, "No data in file '%s'.\n", argv[2]); bu_vls_free(&format_string); rt_db_free_internal(&internal); return GED_ERROR; } } else { temp_char_ptr = strchr("0123456789.+-eE", buf); if (temp_char_ptr != NULL) { /* character read is part of a double */ current_character_double = 1; } else { current_character_double = 0; } } if (previous_character_double && current_character_double) { if (temp_string_index >= temp_string_size) { fclose(fp); bu_vls_printf(gedp->ged_result_str, "Make '%s' failed. ", argv[1]); bu_vls_printf(gedp->ged_result_str, "String representing double too large, exceeds '%d' character limit. ", temp_string_size - 1); report_import_error_location(num_doubles_read, num_doubles_per_point, start_offset_of_current_double, format, gedp->ged_result_str); bu_vls_free(&format_string); rt_db_free_internal(&internal); return GED_ERROR; } temp_string[temp_string_index] = (char)buf; temp_string_index++; } if (previous_character_double && !current_character_double) { if (temp_string_index >= temp_string_size) { fclose(fp); bu_vls_printf(gedp->ged_result_str, "Make '%s' failed. ", argv[1]); bu_vls_printf(gedp->ged_result_str, "String representing double too large, exceeds '%d' character limit. ", temp_string_size - 1); report_import_error_location(num_doubles_read, num_doubles_per_point, start_offset_of_current_double, format, gedp->ged_result_str); bu_vls_free(&format_string); rt_db_free_internal(&internal); return GED_ERROR; } temp_string[temp_string_index] = '\0'; /* do not convert string to double for format character '?' */ if (format != '?') { temp_double = strtod(temp_string, &endp); if (!((endp != temp_string) && (*endp == '\0'))) { fclose(fp); bu_vls_printf(gedp->ged_result_str, "Make '%s' failed. ", argv[1]); bu_vls_printf(gedp->ged_result_str, "Unable to convert string '%s' to double. ", temp_string); report_import_error_location(num_doubles_read, num_doubles_per_point, start_offset_of_current_double, format, gedp->ged_result_str); bu_vls_free(&format_string); rt_db_free_internal(&internal); return GED_ERROR; } num_doubles_read++; } else { temp_double = 0.0; } temp_string_index = 0; found_double = 1; previous_character_double = current_character_double; } if (!previous_character_double && current_character_double) { temp_string[temp_string_index] = (char)buf; temp_string_index++; start_offset_of_current_double = num_characters_read_from_file; previous_character_double = current_character_double; } } /* loop exits when eof encountered (and/or) double found */ if (found_double) { /* insert double into point structure for current point-cloud type */ /* do not attempt to insert double into point structure for format character '?' */ if (format != '?') { switch (type) { case RT_PNT_TYPE_PNT: INSERT_COORDINATE_INTO_STRUCTURE(pnt, format, (temp_double * local2base)); break; case RT_PNT_TYPE_COL: INSERT_COORDINATE_INTO_STRUCTURE(pnt_color, format, (temp_double * local2base)); INSERT_COLOR_INTO_STRUCTURE(pnt_color, format, temp_double); break; case RT_PNT_TYPE_SCA: INSERT_COORDINATE_INTO_STRUCTURE(pnt_scale, format, (temp_double * local2base)); INSERT_SCALE_INTO_STRUCTURE(pnt_scale, format, (temp_double * local2base)); break; case RT_PNT_TYPE_NRM: INSERT_COORDINATE_INTO_STRUCTURE(pnt_normal, format, (temp_double * local2base)); INSERT_NORMAL_INTO_STRUCTURE(pnt_normal, format, (temp_double * local2base)); break; case RT_PNT_TYPE_COL_SCA: INSERT_COORDINATE_INTO_STRUCTURE(pnt_color_scale, format, (temp_double * local2base)); INSERT_COLOR_INTO_STRUCTURE(pnt_color_scale, format, temp_double); INSERT_SCALE_INTO_STRUCTURE(pnt_color_scale, format, (temp_double * local2base)); break; case RT_PNT_TYPE_COL_NRM: INSERT_COORDINATE_INTO_STRUCTURE(pnt_color_normal, format, (temp_double * local2base)); INSERT_COLOR_INTO_STRUCTURE(pnt_color_normal, format, temp_double); INSERT_NORMAL_INTO_STRUCTURE(pnt_color_normal, format, (temp_double * local2base)); break; case RT_PNT_TYPE_SCA_NRM: INSERT_COORDINATE_INTO_STRUCTURE(pnt_scale_normal, format, (temp_double * local2base)); INSERT_SCALE_INTO_STRUCTURE(pnt_scale_normal, format, (temp_double * local2base)); INSERT_NORMAL_INTO_STRUCTURE(pnt_scale_normal, format, (temp_double * local2base)); break; case RT_PNT_TYPE_COL_SCA_NRM: INSERT_COORDINATE_INTO_STRUCTURE(pnt_color_scale_normal, format, (temp_double * local2base)); INSERT_COLOR_INTO_STRUCTURE(pnt_color_scale_normal, format, temp_double); INSERT_SCALE_INTO_STRUCTURE(pnt_color_scale_normal, format, (temp_double * local2base)); INSERT_NORMAL_INTO_STRUCTURE(pnt_color_scale_normal, format, (temp_double * local2base)); break; } } found_double = 0; /* allows loop to continue */ format_string_index++; if (format_string_index >= bu_vls_strlen(&format_string)) { done_processing_format_string = 1; } } } /* loop exits when eof encountered (and/or) all doubles for * a single point are stored in point structure */ if (done_processing_format_string) { /* push single point structure onto linked-list of points * which makeup the point-cloud. */ switch (type) { case RT_PNT_TYPE_PNT: BU_LIST_PUSH(&(((struct pnt *)headPoint)->l), &((struct pnt *)point)->l); break; case RT_PNT_TYPE_COL: BU_LIST_PUSH(&(((struct pnt_color *)headPoint)->l), &((struct pnt_color *)point)->l); break; case RT_PNT_TYPE_SCA: BU_LIST_PUSH(&(((struct pnt_scale *)headPoint)->l), &((struct pnt_scale *)point)->l); break; case RT_PNT_TYPE_NRM: BU_LIST_PUSH(&(((struct pnt_normal *)headPoint)->l), &((struct pnt_normal *)point)->l); break; case RT_PNT_TYPE_COL_SCA: BU_LIST_PUSH(&(((struct pnt_color_scale *)headPoint)->l), &((struct pnt_color_scale *)point)->l); break; case RT_PNT_TYPE_COL_NRM: BU_LIST_PUSH(&(((struct pnt_color_normal *)headPoint)->l), &((struct pnt_color_normal *)point)->l); break; case RT_PNT_TYPE_SCA_NRM: BU_LIST_PUSH(&(((struct pnt_scale_normal *)headPoint)->l), &((struct pnt_scale_normal *)point)->l); break; case RT_PNT_TYPE_COL_SCA_NRM: BU_LIST_PUSH(&(((struct pnt_color_scale_normal *)headPoint)->l), &((struct pnt_color_scale_normal *)point)->l); break; } numPoints++; format_string_index = 0; done_processing_format_string = 0; } } /* loop exits when eof encountered */ if (num_doubles_read < num_doubles_per_point) { bu_vls_printf(gedp->ged_result_str, "Make '%s' failed. Number of values read inconsistent with point-cloud type ", argv[1]); bu_vls_printf(gedp->ged_result_str, "defined by format string '%V'. The number of values read must be an even ", format_string); bu_vls_printf(gedp->ged_result_str, "multiple of %d but read %lu values.\n", num_doubles_per_point, num_doubles_read); bu_vls_free(&format_string); rt_db_free_internal(&internal); return GED_ERROR; } if (num_doubles_read % num_doubles_per_point) { bu_vls_printf(gedp->ged_result_str, "Make '%s' failed. Number of values read inconsistent with point-cloud type ", argv[1]); bu_vls_printf(gedp->ged_result_str, "defined by format string '%V'. The number of values read must be an even ", format_string); bu_vls_printf(gedp->ged_result_str, "multiple of %d but read %lu values.\n", num_doubles_per_point, num_doubles_read); bu_vls_free(&format_string); rt_db_free_internal(&internal); return GED_ERROR; } pnts->count = numPoints; GED_DB_DIRADD(gedp, dp, argv[1], RT_DIR_PHONY_ADDR, 0, RT_DIR_SOLID, (void *)&internal.idb_type, GED_ERROR); GED_DB_PUT_INTERNAL(gedp, dp, &internal, &rt_uniresource, GED_ERROR); bu_vls_free(&format_string); bu_vls_printf(gedp->ged_result_str, "Make '%s' success, %lu values read, %lu points imported.\n", argv[1], num_doubles_read, numPoints); return GED_OK; }