Ejemplo n.º 1
0
/*
 * 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;
}
Ejemplo n.º 2
0
/*
 *  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;
}
Ejemplo n.º 3
0
/*
 * 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;
}
Ejemplo n.º 4
0
/*
 * '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;
}