Revision: 76285
          http://sourceforge.net/p/brlcad/code/76285
Author:   starseeker
Date:     2020-07-08 16:18:01 +0000 (Wed, 08 Jul 2020)
Log Message:
-----------
Pull the g2asc logic from g2asc.c and rough it into the respective gcv plugin 
files.  Not working or close to it - just figuring out which pieces belong 
where.  For v5, once we know what we're writing out we'll know what we need to 
read in - anything added to a .asc file not written by g2asc will promote an 
asc file to an all-up Tcl script needing the full libtclcad logic to evaluate.

Modified Paths:
--------------
    brlcad/trunk/src/libgcv/plugins/asc/asc.cpp
    brlcad/trunk/src/libgcv/plugins/asc/asc_v4.cpp
    brlcad/trunk/src/libgcv/plugins/asc/asc_v5.cpp

Modified: brlcad/trunk/src/libgcv/plugins/asc/asc.cpp
===================================================================
--- brlcad/trunk/src/libgcv/plugins/asc/asc.cpp 2020-07-08 15:09:29 UTC (rev 
76284)
+++ brlcad/trunk/src/libgcv/plugins/asc/asc.cpp 2020-07-08 16:18:01 UTC (rev 
76285)
@@ -37,6 +37,7 @@
 
 extern void asc_read_v4(struct gcv_context *c, const struct gcv_opts *o, 
std::ifstream &fs);
 extern void asc_read_v5(struct gcv_context *c, const struct gcv_opts *o, 
std::ifstream &fs);
+extern void asc_write_v5(struct gcv_context *c, const struct gcv_opts *o, 
const char *dest_path);
 
 static int
 asc_can_read(const char *data)
@@ -111,11 +112,13 @@
 }
 
 static int
-asc_write(struct gcv_context *context, const struct gcv_opts *gcv_options,
-              const void *UNUSED(options_data), const char *dest_path)
+asc_write(struct gcv_context *c, const struct gcv_opts *o,
+              const void *UNUSED(odata), const char *dest_path)
 {
-    if (!context || !gcv_options || !dest_path) return 0;
+    if (!c || !o || !dest_path) return 0;
     bu_log("asc write\n");
+    // TODO - check for version option
+    asc_write_v5(c, o, dest_path);
     return 1;
 }
 

Modified: brlcad/trunk/src/libgcv/plugins/asc/asc_v4.cpp
===================================================================
--- brlcad/trunk/src/libgcv/plugins/asc/asc_v4.cpp      2020-07-08 15:09:29 UTC 
(rev 76284)
+++ brlcad/trunk/src/libgcv/plugins/asc/asc_v4.cpp      2020-07-08 16:18:01 UTC 
(rev 76285)
@@ -32,6 +32,8 @@
 #include <sstream>
 #include <string>
 
+#include "rt/db4.h"
+#include "raytrace.h"
 #include "gcv/api.h"
 #include "gcv/util.h"
 
@@ -48,9 +50,980 @@
        std::cout << sline << "\n";
     }
     return 1;
+}
 
+static int     combdump(void);
+static void    idendump(void), polyhead_asc(void), polydata_asc(void);
+static void    soldump(void), extrdump(void), sketchdump(void);
+static void    membdump(union record *rp), arsadump(void), arsbdump(void);
+static void    materdump(void), bspldump(void), bsurfdump(void);
+static void    pipe_dump(void), particle_dump(void), dump_pipe_segs(char *, 
struct bu_list *);
+static void    arbn_dump(void), cline_dump(void), bot_dump(void);
+static void    nmg_dump(void);
+static void    strsol_dump(void);
+static char *  strchop(char *str, size_t len);
+
+const mat_t id_mat = MAT_INIT_IDN; /* identity matrix for pipes */
+#define CH(x)  strchop(x, sizeof(x))
+union record   record;         /* GED database record */
+FILE   *ifp;
+FILE   *ofp;
+
+/*
+ *  Take a database name and null-terminate it,
+ *  converting unprintable characters to something printable.
+ *  Here we deal with names not being null-terminated.
+ */
+static char *
+encode_name(char *str)
+{
+    static char buf[NAMESIZE+1];
+    char *ip = str;
+    char *op = buf;
+    int warn = 0;
+
+    while (op < &buf[NAMESIZE]) {
+       if (*ip == '\0')  break;
+       if (isprint((int)*ip) && !isspace((int)*ip)) {
+           *op++ = *ip++;
+       }  else  {
+           *op++ = '@';
+           ip++;
+           warn = 1;
+       }
+    }
+    *op = '\0';
+    if (warn) {
+       fprintf(stderr,
+                     "g2asc: Illegal char in object name, converted to '%s'\n",
+                     buf);
+    }
+    if (op == buf) {
+       /* Null input name */
+       fprintf(stderr,
+                     "g2asc:  NULL object name converted to -=NULL=-\n");
+       
+       // TODO
+       // return "-=NULL=-";
+       return NULL;
+    }
+    return buf;
 }
 
+
+/*
+ *  Take "ngran" granules, and put them in memory.
+ *  The first granule comes from the global extern "record",
+ *  the remainder are read from ifp.
+ */
+static void
+get_ext(struct bu_external *ep, size_t ngran)
+{
+    size_t count;
+
+    BU_EXTERNAL_INIT(ep);
+
+    ep->ext_nbytes = ngran * sizeof(union record);
+    ep->ext_buf = (uint8_t *)bu_malloc(ep->ext_nbytes, "get_ext ext_buf");
+
+    /* Copy the freebie (first) record into the array of records.  */
+    memcpy((char *)ep->ext_buf, (char *)&record, sizeof(union record));
+    if (ngran <= 1)  return;
+
+    count = fread(((char *)ep->ext_buf)+sizeof(union record),
+                  sizeof(union record), ngran-1, ifp);
+    if (count != (size_t)ngran-1) {
+       fprintf(stderr,
+               "g2asc: get_ext:  wanted to read %lu granules, got %lu\n",
+               (unsigned long)ngran-1, (unsigned long)count);
+       bu_exit(1, NULL);
+    }
+}
+
+static void
+nmg_dump(void)
+{
+    union record rec;
+    long struct_count[26];
+    size_t i, granules;
+    size_t j, k;
+
+    /* just in case someone changes the record size */
+    if (sizeof(union record)%32)
+    {
+       fprintf(stderr, "g2asc: nmg_dump cannot work with records not multiple 
of 32\n");
+       bu_exit(-1, NULL);
+    }
+
+    /* get number of granules needed for this NMG */
+    granules = ntohl(*(uint32_t *)record.nmg.N_count);
+
+    /* get the array of structure counts */
+    for (j = 0; j < 26; j++)
+       struct_count[j] = ntohl(*(uint32_t *)&record.nmg.N_structs[j*4]);
+
+    /* output some header info */
+    fprintf(ofp,  "%c %d %.16s %lu\n",
+                 record.nmg.N_id,      /* N */
+                 record.nmg.N_version, /* NMG version */
+                 record.nmg.N_name,    /* solid name */
+                 (unsigned long)granules);             /* number of additional 
granules */
+
+    /* output the structure counts */
+    for (j = 0; j < 26; j++)
+       fprintf(ofp,  " %ld", struct_count[j]);
+    (void)fputc('\n', ofp);
+
+    /* dump the reminder in hex format */
+    for (i = 0; i < granules; i++) {
+       char *cp;
+       /* Read the record */
+       if (!fread((char *)&rec, sizeof record, 1, ifp)) {
+           fprintf(stderr, "Error reading nmg granules\n");
+           bu_exit(-1, NULL);
+       }
+       cp = (char *)&rec;
+
+       /* 32 bytes per line */
+       for (k = 0; k < sizeof(union record)/32; k++) {
+           for (j = 0; j < 32; j++)
+               fprintf(ofp,  "%02x", (0xff & (*cp++)));         /* two hex 
digits per byte */
+           fputc('\n', ofp);
+       }
+    }
+}
+
+static void
+strsol_dump(void)      /* print out strsol solid info */
+{
+    union record rec[DB_SS_NGRAN];
+    char *cp;
+
+    /* get all the strsol granules */
+    rec[0] = record;   /* struct copy the current record */
+
+    /* read the rest from ifp */
+    if (!fread((char *)&rec[1], sizeof record, DB_SS_NGRAN-1, ifp))
+    {
+       fprintf(stderr, "Error reading strsol granules\n");
+       bu_exit(-1, NULL);
+    }
+
+    /* make sure that at least the last byte is null */
+    cp = (char *)&rec[DB_SS_NGRAN-1];
+    cp += (sizeof(union record) - 1);
+    *cp = '\0';
+
+    fprintf(ofp,  "%c %.16s %.16s %s\n",
+                 rec[0].ss.ss_id,      /* s */
+                 rec[0].ss.ss_keyword, /* "ebm", "vol", or ??? */
+                 rec[0].ss.ss_name,    /* solid name */
+                 rec[0].ss.ss_args);   /* everything else */
+
+}
+
+static void
+idendump(void) /* Print out Ident record information */
+{
+    fprintf(ofp,  "%c %d %.6s\n",
+                 record.i.i_id,                        /* I */
+                 record.i.i_units,             /* units */
+                 CH(record.i.i_version)                /* version */
+       );
+    fprintf(ofp,  "%.72s\n",
+                 CH(record.i.i_title)  /* title or description */
+       );
+
+    /* Print a warning message on stderr if versions differ */
+    if (!BU_STR_EQUAL(record.i.i_version, ID_VERSION)) {
+       fprintf(stderr,
+                     "g2asc: File is version (%s), Program is version (%s)\n",
+                     record.i.i_version, ID_VERSION);
+    }
+}
+
+static void
+polyhead_asc(void)     /* Print out Polyhead record information */
+{
+    fprintf(ofp, "%c ", record.p.p_id);                /* P */
+    fprintf(ofp, "%.16s", encode_name(record.p.p_name));       /* unique name 
*/
+    fprintf(ofp, "\n");                        /* Terminate w/ a newline */
+}
+
+static void
+polydata_asc(void)     /* Print out Polydata record information */
+{
+    int i, j;
+
+    fprintf(ofp, "%c ", record.q.q_id);                /* Q */
+    fprintf(ofp, "%d", record.q.q_count);              /* # of vertices <= 5 */
+    for (i = 0; i < 5; i++) {
+       /* [5][3] vertices */
+       for (j = 0; j < 3; j++) {
+           fprintf(ofp, " %.12e", record.q.q_verts[i][j]);
+       }
+    }
+    for (i = 0; i < 5; i++) {
+       /* [5][3] normals */
+       for (j = 0; j < 3; j++) {
+           fprintf(ofp, " %.12e", record.q.q_norms[i][j]);
+       }
+    }
+    fprintf(ofp, "\n");                        /* Terminate w/ a newline */
+}
+
+static void
+soldump(void)  /* Print out Solid record information */
+{
+    int i;
+
+    fprintf(ofp, "%c ", record.s.s_id);        /* S */
+    fprintf(ofp, "%d ", record.s.s_type);      /* GED primitive type */
+    fprintf(ofp, "%.16s ", encode_name(record.s.s_name));      /* unique name 
*/
+    fprintf(ofp, "%d", record.s.s_cgtype);/* COMGEOM solid type */
+    for (i = 0; i < 24; i++)
+       fprintf(ofp, " %.12e", record.s.s_values[i]); /* parameters */
+    fprintf(ofp, "\n");                        /* Terminate w/ a newline */
+}
+
+static void
+cline_dump(void)
+{
+    size_t ngranules;  /* number of granules, total */
+    char *name;
+    struct rt_cline_internal *cli;
+    struct bu_external ext;
+    struct rt_db_internal intern;
+
+    name = record.cli.cli_name;
+
+    ngranules = 1;
+    get_ext(&ext, ngranules);
+
+    /* Hand off to librt's import() routine */
+    RT_DB_INTERNAL_INIT(&intern);
+    if ((OBJ[ID_CLINE].ft_import4(&intern, &ext, id_mat, DBI_NULL, 
&rt_uniresource)) != 0) {
+       fprintf(stderr, "g2asc: cline import failure\n");
+       bu_exit(-1, NULL);
+    }
+
+    cli = (struct rt_cline_internal *)intern.idb_ptr;
+    RT_CLINE_CK_MAGIC(cli);
+
+    fprintf(ofp, "%c ", DBID_CLINE);   /* c */
+    fprintf(ofp, "%.16s ", name);      /* unique name */
+    fprintf(ofp, "%26.20e %26.20e %26.20e ", V3ARGS(cli->v));
+    fprintf(ofp, "%26.20e %26.20e %26.20e ", V3ARGS(cli->h));
+    fprintf(ofp, "%26.20e %26.20e", cli->radius, cli->thickness);
+    fprintf(ofp, "\n");                        /* Terminate w/ a newline */
+
+    rt_db_free_internal(&intern);
+    bu_free_external(&ext);
+}
+
+static void
+bot_dump(void)
+{
+    size_t ngranules;
+    char *name;
+    struct rt_bot_internal *bot;
+    struct bu_external ext;
+    struct rt_db_internal intern;
+    size_t i;
+
+    name = record.bot.bot_name;
+    ngranules = ntohl(*(uint32_t *)record.bot.bot_nrec) + 1;
+    get_ext(&ext, ngranules);
+
+    /* Hand off to librt's import() routine */
+    RT_DB_INTERNAL_INIT(&intern);
+    if ((OBJ[ID_BOT].ft_import4(&intern, &ext, id_mat, DBI_NULL, 
&rt_uniresource)) != 0) {
+       fprintf(stderr, "g2asc: bot import failure\n");
+       bu_exit(-1, NULL);
+    }
+
+    bot = (struct rt_bot_internal *)intern.idb_ptr;
+    RT_BOT_CK_MAGIC(bot);
+
+    fprintf(ofp, "%c ", DBID_BOT);     /* t */
+    fprintf(ofp, "%.16s ", name);      /* unique name */
+    fprintf(ofp, "%d ", bot->mode);
+    fprintf(ofp, "%d ", bot->orientation);
+    fprintf(ofp, "%d ", 0);    /* was error_mode */
+    fprintf(ofp, "%lu ", (unsigned long)bot->num_vertices);
+    fprintf(ofp, "%lu", (unsigned long)bot->num_faces);
+    fprintf(ofp, "\n");
+
+    for (i = 0; i < bot->num_vertices; i++)
+       fprintf(ofp,  " %lu: %26.20e %26.20e %26.20e\n", (unsigned long)i, 
V3ARGS(&bot->vertices[i*3]));
+    if (bot->mode == RT_BOT_PLATE) {
+       struct bu_vls vls = BU_VLS_INIT_ZERO;
+
+       for (i = 0; i < bot->num_faces; i++)
+           fprintf(ofp,  "     %lu: %d %d %d %26.20e\n", (unsigned long)i, 
V3ARGS(&bot->faces[i*3]), bot->thickness[i]);
+       bu_bitv_to_hex(&vls, bot->face_mode);
+       fprintf(ofp,  " %s\n", bu_vls_addr(&vls));
+       bu_vls_free(&vls);
+    } else {
+       for (i = 0; i < bot->num_faces; i++)
+           fprintf(ofp,  "     %lu: %d %d %d\n", (unsigned long)i, 
V3ARGS(&bot->faces[i*3]));
+    }
+
+    rt_db_free_internal(&intern);
+    bu_free_external(&ext);
+}
+
+static void
+pipe_dump(void)        /* Print out Pipe record information */
+{
+
+    size_t ngranules;  /* number of granules, total */
+    char *name;
+    struct rt_pipe_internal *pipeip;           /* want a struct for the head, 
not a ptr. */
+    struct bu_external ext;
+    struct rt_db_internal intern;
+
+    ngranules = ntohl(*(uint32_t *)record.pwr.pwr_count) + 1;
+    name = record.pwr.pwr_name;
+
+    get_ext(&ext, ngranules);
+
+    /* Hand off to librt's import() routine */
+    RT_DB_INTERNAL_INIT(&intern);
+    if ((OBJ[ID_PIPE].ft_import4(&intern, &ext, id_mat, NULL, 
&rt_uniresource)) != 0) {
+       fprintf(stderr, "g2asc: pipe import failure\n");
+       bu_exit(-1, NULL);
+    }
+
+    pipeip = (struct rt_pipe_internal *)intern.idb_ptr;
+    RT_PIPE_CK_MAGIC(pipeip);
+
+    /* send the doubly linked list off to dump_pipe_segs(), which
+     * will print all the information.
+     */
+
+    dump_pipe_segs(name, &pipeip->pipe_segs_head);
+
+    rt_db_free_internal(&intern);
+    bu_free_external(&ext);
+}
+
+static void
+dump_pipe_segs(char *name, struct bu_list *headp)
+{
+
+    struct wdb_pipe_pnt *sp;
+
+    fprintf(ofp, "%c %.16s\n", DBID_PIPE, name);
+
+    /* print parameters for each point: one point per line */
+
+    for (BU_LIST_FOR(sp, wdb_pipe_pnt, headp)) {
+       fprintf(ofp,  "%26.20e %26.20e %26.20e %26.20e %26.20e %26.20e\n",
+               sp->pp_id, sp->pp_od, sp->pp_bendradius, V3ARGS(sp->pp_coord));
+    }
+    fprintf(ofp,  "END_PIPE %s\n", name);
+}
+
+/*
+ * Print out Particle record information.
+ * Note that particles fit into one granule only.
+ */
+static void
+particle_dump(void)
+{
+    struct rt_part_internal    *part;  /* head for the structure */
+    struct bu_external ext;
+    struct rt_db_internal      intern;
+
+    get_ext(&ext, 1);
+
+    /* Hand off to librt's import() routine */
+    RT_DB_INTERNAL_INIT(&intern);
+    if ((OBJ[ID_PARTICLE].ft_import4(&intern, &ext, id_mat, NULL, 
&rt_uniresource)) != 0) {
+       fprintf(stderr, "g2asc: particle import failure\n");
+       bu_exit(-1, NULL);
+    }
+
+    part = (struct rt_part_internal *)intern.idb_ptr;
+    RT_PART_CK_MAGIC(part);
+
+    /* Particle type is picked up on here merely to ensure receiving
+     * valid data.  The type is not used any further.
+     */
+
+    switch (part->part_type) {
+       case RT_PARTICLE_TYPE_SPHERE:
+           break;
+       case RT_PARTICLE_TYPE_CYLINDER:
+           break;
+       case RT_PARTICLE_TYPE_CONE:
+           break;
+       default:
+           fprintf(stderr, "g2asc: no particle type %d\n", part->part_type);
+           bu_exit(-1, NULL);
+    }
+
+    fprintf(ofp, "%c %.16s %26.20e %26.20e %26.20e %26.20e %26.20e %26.20e 
%26.20e %26.20e\n",
+           record.part.p_id, record.part.p_name,
+           part->part_V[X],
+           part->part_V[Y],
+           part->part_V[Z],
+           part->part_H[X],
+           part->part_H[Y],
+           part->part_H[Z],
+           part->part_vrad, part->part_hrad);
+}
+
+
+/*
+ *  Print out arbn information.
+ *
+ */
+static void
+arbn_dump(void)
+{
+    size_t ngranules;  /* number of granules to be read */
+    size_t i;          /* a counter */
+    char *name;
+    struct rt_arbn_internal *arbn;
+    struct bu_external ext;
+    struct rt_db_internal intern;
+
+    ngranules = ntohl(*(uint32_t *)record.n.n_grans) + 1;
+    name = record.n.n_name;
+
+    get_ext(&ext, ngranules);
+
+    /* Hand off to librt's import() routine */
+    RT_DB_INTERNAL_INIT(&intern);
+    if ((OBJ[ID_ARBN].ft_import4(&intern, &ext, id_mat, NULL, 
&rt_uniresource)) != 0) {
+       fprintf(stderr, "g2asc: arbn import failure\n");
+       bu_exit(-1, NULL);
+    }
+
+    arbn = (struct rt_arbn_internal *)intern.idb_ptr;
+    RT_ARBN_CK_MAGIC(arbn);
+
+    fprintf(ofp, "%c %.16s %lu\n", 'n', name, (unsigned long)arbn->neqn);
+    for (i = 0; i < arbn->neqn; i++) {
+       fprintf(ofp, "n %26.20e %20.26e %26.20e %26.20e\n",
+               arbn->eqn[i][X], arbn->eqn[i][Y],
+               arbn->eqn[i][Z], arbn->eqn[i][3]);
+    }
+
+    rt_db_free_internal(&intern);
+    bu_free_external(&ext);
+}
+
+
+/*
+ *  Note that for compatibility with programs such as FRED that
+ *  (inappropriately) read .asc files, the member count has to be
+ *  recalculated here.
+ *
+ *  Returns -
+ *     0       converted OK
+ *     1       converted OK, left next record in global "record" for reuse.
+ */
+static int
+combdump(void) /* Print out Combination record information */
+{
+    int        m1, m2;         /* material property flags */
+    struct bu_list     head;
+    struct mchain {
+       struct bu_list  l;
+       union record    r;
+    };
+    struct mchain      *mp;
+    struct mchain      *ret_mp = (struct mchain *)0;
+    int                mcount;
+
+    /*
+     *  Gobble up all subsequent member records, so that
+     *  an accurate count of them can be output.
+     */
+    BU_LIST_INIT(&head);
+    mcount = 0;
+    while (1) {
+       BU_GET(mp, struct mchain);
+       if (fread((char *)&mp->r, sizeof(mp->r), 1, ifp) != 1
+            || feof(ifp))
+           break;
+       if (mp->r.u_id != ID_MEMB) {
+           ret_mp = mp;        /* Handle it later */
+           break;
+       }
+       BU_LIST_INSERT(&head, &(mp->l));
+       mcount++;
+    }
+
+    /*
+     *  Output the combination
+     */
+    fprintf(ofp, "%c ", record.c.c_id);                /* C */
+    switch (record.c.c_flags) {
+       case DBV4_REGION:
+           fprintf(ofp, "Y ");                 /* Y if `R' */
+           break;
+       case DBV4_NON_REGION_NULL:
+       case DBV4_NON_REGION:
+           fprintf(ofp, "N ");                 /* N if ` ' or '\0' */
+           break;
+       case DBV4_REGION_FASTGEN_PLATE:
+           fprintf(ofp, "P ");
+           break;
+       case DBV4_REGION_FASTGEN_VOLUME:
+           fprintf(ofp, "V ");
+           break;
+    }
+    fprintf(ofp, "%.16s ", encode_name(record.c.c_name));      /* unique name 
*/
+    fprintf(ofp, "%d ", record.c.c_regionid);  /* region ID code */
+    fprintf(ofp, "%d ", record.c.c_aircode);   /* air space code */
+
+    /* DEPRECATED: # of members */
+    fprintf(ofp, "%d ", mcount);
+
+    /* DEPRECATED: COMGEOM region # */
+    fprintf(ofp, "%d ", 0 /* was record.c.c_num */);
+
+    fprintf(ofp, "%d ", record.c.c_material);  /* material code */
+    fprintf(ofp, "%d ", record.c.c_los);               /* equiv. LOS est. */
+    fprintf(ofp, "%d %d %d %d ",
+                 record.c.c_override ? 1 : 0,
+                 record.c.c_rgb[0],
+                 record.c.c_rgb[1],
+                 record.c.c_rgb[2]);
+    m1 = m2 = 0;
+    if (isprint((int)record.c.c_matname[0])) {
+       m1 = 1;
+       if (record.c.c_matparm[0])
+           m2 = 1;
+    }
+    fprintf(ofp, "%d %d", m1, m2);
+    switch (record.c.c_inherit) {
+       case DB_INH_HIGHER:
+           fprintf(ofp, " %d", DB_INH_HIGHER);
+           break;
+       default:
+       case DB_INH_LOWER:
+           fprintf(ofp, " %d", DB_INH_LOWER);
+           break;
+    }
+    fprintf(ofp, "\n");                        /* Terminate w/ a newline */
+
+    if (m1)
+       fprintf(ofp, "%.32s\n", CH(record.c.c_matname));
+    if (m2)
+       fprintf(ofp, "%.60s\n", CH(record.c.c_matparm));
+
+    /*
+     *  Output the member records now
+     */
+    while (BU_LIST_WHILE(mp, mchain, &head)) {
+       membdump(&mp->r);
+       BU_LIST_DEQUEUE(&mp->l);
+       BU_PUT(mp, struct mchain);
+    }
+
+    if (ret_mp) {
+       memcpy((char *)&record, (char *)&ret_mp->r, sizeof(record));
+       BU_PUT(ret_mp, struct mchain);
+       return 1;
+    }
+    return 0;
+}
+
+/*
+ *  Print out Member record information.
+ *  Intended to be called by combdump only.
+ */
+static void
+membdump(union record *rp)
+{
+    int i;
+
+    fprintf(ofp, "%c ", rp->M.m_id);           /* M */
+    fprintf(ofp, "%c ", rp->M.m_relation);     /* Boolean oper. */
+    fprintf(ofp, "%.16s ", encode_name(rp->M.m_instname));     /* referred-to 
obj. */
+    for (i = 0; i < 16; i++)                   /* homogeneous transform matrix 
*/
+       fprintf(ofp, "%.12e ", rp->M.m_mat[i]);
+    fprintf(ofp, "%d", 0);                     /* was COMGEOM solid # */
+    fprintf(ofp, "\n");                                /* Terminate w/ nl */
+}
+
+static void
+arsadump(void) /* Print out ARS record information */
+{
+    int i;
+    int length;        /* Keep track of number of ARS B records */
+
+    fprintf(ofp, "%c ", record.a.a_id);        /* A */
+    fprintf(ofp, "%d ", record.a.a_type);      /* primitive type */
+    fprintf(ofp, "%.16s ", encode_name(record.a.a_name));      /* unique name 
*/
+    fprintf(ofp, "%d ", record.a.a_m); /* # of curves */
+    fprintf(ofp, "%d ", record.a.a_n); /* # of points per curve */
+    fprintf(ofp, "%d ", record.a.a_curlen);/* # of granules per curve */
+    fprintf(ofp, "%d ", record.a.a_totlen);/* # of granules for ARS */
+    fprintf(ofp, "%.12e ", record.a.a_xmax);   /* max x coordinate */
+    fprintf(ofp, "%.12e ", record.a.a_xmin);   /* min x coordinate */
+    fprintf(ofp, "%.12e ", record.a.a_ymax);   /* max y coordinate */
+    fprintf(ofp, "%.12e ", record.a.a_ymin);   /* min y coordinate */
+    fprintf(ofp, "%.12e ", record.a.a_zmax);   /* max z coordinate */
+    fprintf(ofp, "%.12e", record.a.a_zmin);    /* min z coordinate */
+    fprintf(ofp, "\n");                        /* Terminate w/ a newline */
+
+    length = (int)record.a.a_totlen;   /* Get # of ARS B records */
+
+    for (i = 0; i < length; i++) {
+       arsbdump();
+    }
+}
+
+static void
+arsbdump(void) /* Print out ARS B record information */
+{
+    int i;
+    size_t ret;
+
+    /* Read in a member record for processing */
+    ret = fread((char *)&record, sizeof record, 1, ifp);
+    if (ret != 1)
+       perror("fread");
+    fprintf(ofp, "%c ", record.b.b_id);                /* B */
+    fprintf(ofp, "%d ", record.b.b_type);              /* primitive type */
+    fprintf(ofp, "%d ", record.b.b_n);         /* current curve # */
+    fprintf(ofp, "%d", record.b.b_ngranule);   /* current granule */
+    for (i = 0; i < 24; i++) {
+       /* [8*3] vectors */
+       fprintf(ofp, " %.12e", record.b.b_values[i]);
+    }
+    fprintf(ofp, "\n");                        /* Terminate w/ a newline */
+}
+
+static void
+materdump(void)        /* Print out material description record information */
+{
+    fprintf(ofp,  "%c %d %d %d %d %d %d\n",
+                 record.md.md_id,                      /* m */
+                 record.md.md_flags,                   /* UNUSED */
+                 record.md.md_low,     /* low end of region IDs affected */
+                 record.md.md_hi,      /* high end of region IDs affected */
+                 record.md.md_r,
+                 record.md.md_g,               /* color of regions: 0..255 */
+                 record.md.md_b);
+}
+
+static void
+bspldump(void) /* Print out B-spline solid description record information */
+{
+    fprintf(ofp,  "%c %.16s %d\n",
+                 record.B.B_id,                /* b */
+                 encode_name(record.B.B_name), /* unique name */
+                 record.B.B_nsurf);    /* # of surfaces in this solid */
+}
+
+static void
+bsurfdump(void)        /* Print d-spline surface description record 
information */
+{
+    size_t i;
+    float *vp;
+    size_t nbytes, count;
+    float *fp;
+
+    fprintf(ofp,  "%c %d %d %d %d %d %d %d %d %d\n",
+                 record.d.d_id,                /* D */
+                 record.d.d_order[0],  /* order of u and v directions */
+                 record.d.d_order[1],  /* order of u and v directions */
+                 record.d.d_kv_size[0],        /* knot vector size (u and v) */
+                 record.d.d_kv_size[1],        /* knot vector size (u and v) */
+                 record.d.d_ctl_size[0],       /* control mesh size (u and v) 
*/
+                 record.d.d_ctl_size[1],       /* control mesh size (u and v) 
*/
+                 record.d.d_geom_type, /* geom type 3 or 4 */
+                 record.d.d_nknots,    /* # granules of knots */
+                 record.d.d_nctls);    /* # granules of ctls */
+    /*
+     * The b_surf_head record is followed by
+     * d_nknots granules of knot vectors (first u, then v),
+     * and then by d_nctls granules of control mesh information.
+     * Note that neither of these have an ID field!
+     *
+     * B-spline surface record, followed by
+     * d_kv_size[0] floats,
+     * d_kv_size[1] floats,
+     * padded to d_nknots granules, followed by
+     * ctl_size[0]*ctl_size[1]*geom_type floats,
+     * padded to d_nctls granules.
+     *
+     * IMPORTANT NOTE: granule == sizeof(union record)
+     */
+
+    /* Malloc and clear memory for the KNOT DATA and read it */
+    nbytes = record.d.d_nknots * sizeof(union record);
+    vp = (float *)bu_calloc((unsigned int)nbytes, 1, "KNOT DATA");
+    fp = vp;
+    count = fread((char *)fp, 1, nbytes, ifp);
+    if (count != nbytes) {
+       fprintf(stderr, "g2asc: spline knot read failure\n");
+       bu_exit(1, NULL);
+    }
+    /* Print the knot vector information */
+    count = record.d.d_kv_size[0] + record.d.d_kv_size[1];
+    for (i = 0; i < count; i++) {
+       fprintf(ofp, "%.12e\n", *vp++);
+    }
+    /* Free the knot data memory */
+    (void)bu_free((char *)fp, "KNOT DATA");
+
+    /* Malloc and clear memory for the CONTROL MESH data and read it */
+    nbytes = record.d.d_nctls * sizeof(union record);
+    vp = (float *)bu_calloc((unsigned int)nbytes, 1, "CONTROL MESH");
+    fp = vp;
+    count = fread((char *)fp, 1, nbytes, ifp);
+    if (count != nbytes) {
+       fprintf(stderr, "g2asc: control mesh read failure\n");
+       bu_exit(1, NULL);
+    }
+    /* Print the control mesh information */
+    count = record.d.d_ctl_size[0] * record.d.d_ctl_size[1] *
+       record.d.d_geom_type;
+    for (i = 0; i < count; i++) {
+       fprintf(ofp, "%.12e\n", *vp++);
+    }
+    /* Free the control mesh memory */
+    (void)bu_free((char *)fp, "CONTROL MESH");
+}
+
+/*
+ *  Take a string and a length, and null terminate,
+ *  converting unprintable characters to something printable.
+ */
+static char *
+strchop(char *str, size_t len)
+{
+    static char buf[10000] = {0};
+    char *ip = str;
+    char *op = buf;
+    int warn = 0;
+    char *ep;
+
+    CLAMP(len, 1, sizeof(buf)-2);
+
+    ep = &buf[len-1];          /* Leave room for null */
+    while (op < ep) {
+       if (*ip == '\0')  break;
+       if ((int)isprint((int)*ip) || isspace((int)*ip)) {
+           *op++ = *ip++;
+       }  else  {
+           *op++ = '@';
+           ip++;
+           warn = 1;
+       }
+    }
+    *op = '\0';
+    if (warn) {
+       fprintf(stderr,
+                     "g2asc: Illegal char in string, converted to '%s'\n",
+                     buf);
+    }
+    if (op == buf) {
+       /* Null input name */
+       fprintf(stderr,
+                     "g2asc:  NULL string converted to -=STRING=-\n");
+       // TODO
+       //return "-=STRING=-";
+       return NULL;
+    }
+    return buf;
+}
+
+static void
+extrdump(void)
+{
+    struct rt_extrude_internal *extr;
+    int                                ngranules;
+    char                               *myname;
+    struct bu_external         ext;
+    struct rt_db_internal              intern;
+
+    myname = record.extr.ex_name;
+    ngranules = ntohl(*(uint32_t *)record.extr.ex_count) + 1;
+    get_ext(&ext, ngranules);
+
+    /* Hand off to librt's import() routine */
+    RT_DB_INTERNAL_INIT(&intern);
+    if ((OBJ[ID_EXTRUDE].ft_import4(&intern, &ext, id_mat, DBI_NULL, 
&rt_uniresource)) != 0) {
+       fprintf(stderr, "g2asc: extrusion import failure\n");
+       bu_exit(-1, NULL);
+    }
+
+    extr = (struct rt_extrude_internal *)intern.idb_ptr;
+    RT_EXTRUDE_CK_MAGIC(extr);
+
+    fprintf(ofp, "%c ", DBID_EXTR);    /* e */
+    fprintf(ofp, "%.16s ", encode_name(myname));       /* unique name */
+    fprintf(ofp, "%.16s ", encode_name(extr->sketch_name));
+    fprintf(ofp, "%d ", extr->keypoint);
+    fprintf(ofp, "%.12e %.12e %.12e ", V3ARGS(extr->V));
+    fprintf(ofp, "%.12e %.12e %.12e ", V3ARGS(extr->h));
+    fprintf(ofp, "%.12e %.12e %.12e ", V3ARGS(extr->u_vec));
+    fprintf(ofp, "%.12e %.12e %.12e\n", V3ARGS(extr->v_vec));
+}
+
+static void
+sketchdump(void)
+{
+    struct rt_sketch_internal *skt;
+    size_t ngranules;
+    char *myname;
+    struct bu_external ext;
+    struct rt_db_internal intern;
+    size_t i, j;
+    struct rt_curve *crv;
+
+    myname = record.skt.skt_name;
+    ngranules = ntohl(*(uint32_t *)record.skt.skt_count) + 1;
+    get_ext(&ext, ngranules);
+
+    /* Hand off to librt's import() routine */
+    RT_DB_INTERNAL_INIT(&intern);
+    if ((OBJ[ID_SKETCH].ft_import4(&intern, &ext, id_mat, DBI_NULL, 
&rt_uniresource)) != 0) {
+       fprintf(stderr, "g2asc: sketch import failure\n");
+       bu_exit(-1, NULL);
+    }
+
+    skt = (struct rt_sketch_internal *)intern.idb_ptr;
+    RT_SKETCH_CK_MAGIC(skt);
+    crv = &skt->curve;
+    fprintf(ofp, "%c ", DBID_SKETCH); /* d */
+    fprintf(ofp, "%.16s ", encode_name(myname));  /* unique name */
+    fprintf(ofp, "%.12e %.12e %.12e ", V3ARGS(skt->V));
+    fprintf(ofp, "%.12e %.12e %.12e ", V3ARGS(skt->u_vec));
+    fprintf(ofp, "%.12e %.12e %.12e ", V3ARGS(skt->v_vec));
+    fprintf(ofp, "%lu %lu\n", (unsigned long)skt->vert_count, (unsigned 
long)crv->count);
+    for (i = 0; i < skt->vert_count; i++)
+       fprintf(ofp, " %.12e %.12e", V2ARGS(skt->verts[i]));
+    fprintf(ofp, "\n");
+
+    for (j = 0; j < crv->count; j++) {
+       long *lng;
+       struct line_seg *lsg;
+       struct carc_seg *csg;
+       struct nurb_seg *nsg;
+       int k;
+
+       lng = (long *)crv->segment[j];
+       switch (*lng) {
+           case CURVE_LSEG_MAGIC:
+               lsg = (struct line_seg *)lng;
+               fprintf(ofp, "  L %d %d %d\n", crv->reverse[j], lsg->start, 
lsg->end);
+               break;
+           case CURVE_CARC_MAGIC:
+               csg = (struct carc_seg *)lng;
+               fprintf(ofp, "  A %d %d %d %.12e %d %d\n", crv->reverse[j], 
csg->start, csg->end,
+                             csg->radius, csg->center_is_left, 
csg->orientation);
+               break;
+           case CURVE_NURB_MAGIC:
+               nsg = (struct nurb_seg *)lng;
+               fprintf(ofp, "  N %d %d %d %d %d\n   ", crv->reverse[j], 
nsg->order, nsg->pt_type,
+                             nsg->k.k_size, nsg->c_size);
+               for (k = 0; k < nsg->k.k_size; k++)
+                   fprintf(ofp, " %.12e", nsg->k.knots[k]);
+               fprintf(ofp, "\n   ");
+               for (k = 0; k < nsg->c_size; k++)
+                   fprintf(ofp, " %d", nsg->ctl_points[k]);
+               fprintf(ofp, "\n");
+               break;
+       }
+    }
+}
+
+int
+asc_write_v4(
+           struct gcv_context *UNUSED(c),
+           const struct gcv_opts *UNUSED(o),
+           const char *dest_path
+           )
+{
+    if (!dest_path) return 0;
+
+top:
+do {
+       /* A v4 record is already in the input buffer */
+       /* Check record type and skip deleted records */
+       switch (record.u_id) {
+           case ID_FREE:
+               continue;
+           case ID_SOLID:
+               soldump();
+               continue;
+           case ID_COMB:
+               if (combdump() > 0)
+                   goto top;
+               continue;
+           case ID_MEMB:
+               fprintf(stderr, "g2asc: stray MEMB record, skipped\n");
+               continue;
+           case ID_ARS_A:
+               arsadump();
+               continue;
+           case ID_P_HEAD:
+               polyhead_asc();
+               continue;
+           case ID_P_DATA:
+               polydata_asc();
+               continue;
+           case ID_IDENT:
+               idendump();
+               continue;
+           case ID_MATERIAL:
+               materdump();
+               continue;
+           case DBID_PIPE:
+               pipe_dump();
+               continue;
+           case DBID_STRSOL:
+               strsol_dump();
+               continue;
+           case DBID_NMG:
+               nmg_dump();
+               continue;
+           case DBID_PARTICLE:
+               particle_dump();
+               continue;
+           case DBID_ARBN:
+               arbn_dump();
+               continue;
+           case DBID_CLINE:
+               cline_dump();
+               continue;
+           case DBID_BOT:
+               bot_dump();
+               continue;
+           case ID_BSOLID:
+               bspldump();
+               continue;
+           case ID_BSURF:
+               bsurfdump();
+               continue;
+           case DBID_SKETCH:
+               sketchdump();
+               continue;
+           case DBID_EXTR:
+               extrdump();
+               continue;
+           default:
+               fprintf(stderr,
+                             "g2asc: unable to convert record type '%c' (0%o), 
skipping\n",
+                             record.u_id, record.u_id);
+               continue;
+       }
+    }  while (fread((char *)&record, sizeof record, 1, ifp) == 1  &&
+              !feof(ifp));
+
+    return 1;
+}
+
 // Local Variables:
 // tab-width: 8
 // mode: C++

Modified: brlcad/trunk/src/libgcv/plugins/asc/asc_v5.cpp
===================================================================
--- brlcad/trunk/src/libgcv/plugins/asc/asc_v5.cpp      2020-07-08 15:09:29 UTC 
(rev 76284)
+++ brlcad/trunk/src/libgcv/plugins/asc/asc_v5.cpp      2020-07-08 16:18:01 UTC 
(rev 76285)
@@ -32,6 +32,8 @@
 #include <sstream>
 #include <string>
 
+#include "bu/units.h"
+#include "raytrace.h"
 #include "gcv/api.h"
 #include "gcv/util.h"
 
@@ -44,6 +46,13 @@
 {
     std::string sline;
     bu_log("Reading v5...\n");
+    /* Commands to handle:
+     *
+     * title
+     * units
+     * attr
+     * put
+     */
     while (std::getline(fs, sline)) {
        std::cout << sline << "\n";
     }
@@ -50,6 +59,211 @@
     return 1;
 }
 
+
+static char *tclified_name=NULL;
+static size_t tclified_name_buffer_len=0;
+
+/*     This routine escapes the '{' and '}' characters in any string and 
returns a static buffer containing the
+ *     resulting string. Used for names and db title on output.
+ *
+ *     NOTE: RETURN OF STATIC BUFFER
+ */
+char *
+tclify_name(const char *name)
+{
+    const char *src=name;
+    char *dest;
+
+    size_t max_len=2 * strlen(name) + 1;
+
+    if (max_len < 2) {
+       return (char *)NULL;
+    }
+
+    if (max_len > tclified_name_buffer_len) {
+       tclified_name_buffer_len = max_len;
+       tclified_name = (char *)bu_realloc(tclified_name, 
tclified_name_buffer_len, "tclified_name buffer");
+    }
+
+    dest = tclified_name;
+
+    while (*src) {
+       if (*src == '{' || *src == '}') {
+           *dest++ = '\\';
+       }
+       *dest++ = *src++;
+    }
+    *dest = '\0';
+
+    return tclified_name;
+}
+
+
+int
+asc_write_v5(
+           struct gcv_context *UNUSED(c),
+           const struct gcv_opts *UNUSED(o),
+           const char *dest_path
+           )
+{
+    FILE    *v5ofp = NULL;
+    if (!dest_path) return 0;
+
+    struct db_i        *dbip;
+    struct directory *dp;
+    const char *u;
+
+    if ((dbip = db_open(dest_path, DB_OPEN_READONLY)) == NULL) {
+       bu_log("Unable to open geometry database file '%s', aborting\n", 
dest_path);
+       return 1;
+    }
+
+    RT_CK_DBI(dbip);
+    if (db_dirbuild(dbip)) {
+       bu_exit(1, "db_dirbuild failed\n");
+    }
+
+    /* write out the title and units special */
+    if (dbip->dbi_title[0]) {
+       fprintf(v5ofp, "title {%s}\n", tclify_name(dbip->dbi_title));
+    } else {
+       fprintf(v5ofp, "title {Untitled BRL-CAD Database}\n");
+    }
+    u = bu_units_string(dbip->dbi_local2base);
+    if (u) {
+       fprintf(v5ofp, "units %s\n", u);
+    }
+    FOR_ALL_DIRECTORY_START(dp, dbip) {
+       struct rt_db_internal   intern;
+       struct bu_attribute_value_set *avs=NULL;
+
+       /* Process the _GLOBAL object */
+       if (dp->d_major_type == DB5_MAJORTYPE_ATTRIBUTE_ONLY && 
dp->d_minor_type == 0) {
+           const char *value;
+           struct bu_attribute_value_set g_avs;
+
+           /* get _GLOBAL attributes */
+           if (db5_get_attributes(dbip, &g_avs, dp)) {
+               bu_log("Failed to find any attributes on _GLOBAL\n");
+               continue;
+           }
+
+           /* save the associated attributes of
+            * _GLOBAL (except for title and units
+            * which were already written out) and
+            * regionid_colortable (which is written out below)
+            */
+           if (g_avs.count) {
+               int printedHeader = 0;
+               for (unsigned int i = 0; i < g_avs.count; i++) {
+                   if (bu_strncmp(g_avs.avp[i].name, "title", 6) == 0) {
+                       continue;
+                   } else if (bu_strncmp(g_avs.avp[i].name, "units", 6) == 0) {
+                       continue;
+                   } else if (bu_strncmp(g_avs.avp[i].name, 
"regionid_colortable", 19) == 0) {
+                       continue;
+                   } else if (strlen(g_avs.avp[i].name) <= 0) {
+                       continue;
+                   }
+                   if (printedHeader == 0) {
+                       fprintf(v5ofp, "attr set {_GLOBAL}");
+                       printedHeader = 1;
+                   }
+                   fprintf(v5ofp, " {%s} {%s}", g_avs.avp[i].name, 
g_avs.avp[i].value);
+               }
+               if (printedHeader == 1)
+                   fprintf(v5ofp, "\n");
+           }
+
+           value = bu_avs_get(&g_avs, "regionid_colortable");
+           if (!value)
+               continue;
+           /* TODO - do this without Tcl */
+#if 0
+           size_t list_len;
+           list = Tcl_NewStringObj(value, -1);
+           {
+               int llen;
+               if (Tcl_ListObjLength(interp, list, &llen) != TCL_OK) {
+                   bu_log("Failed to get length of region color table!!\n");
+                   continue;
+               }
+               list_len = (size_t)llen;
+           }
+           for (i = 0; i < list_len; i++) {
+               if (Tcl_ListObjIndex(interp, list, i, &obj) != TCL_OK) {
+                   bu_log("Cannot get entry %d from the color table!!\n",
+                           i);
+                   continue;
+               }
+               fprintf(v5ofp, "color %s\n",
+                       Tcl_GetStringFromObj(obj, NULL));
+           }
+#endif
+           bu_avs_free(&g_avs);
+           continue;
+       }
+
+       if (rt_db_get_internal(&intern, dp, dbip, NULL, &rt_uniresource) < 0) {
+           bu_log("Unable to read '%s', skipping\n", dp->d_namep);
+           continue;
+       }
+       if (!intern.idb_meth->ft_get) {
+           bu_log("Unable to get '%s' (unimplemented), skipping\n", 
dp->d_namep);
+           continue;
+       }
+
+       if (dp->d_flags & RT_DIR_COMB) {
+           struct bu_vls logstr = BU_VLS_INIT_ZERO;
+
+           if (intern.idb_meth->ft_get(&logstr, &intern, "tree") != 0) {
+               rt_db_free_internal(&intern);
+               bu_log("Unable to export '%s', skipping: %s\n", dp->d_namep, 
bu_vls_cstr(&logstr));
+               bu_vls_free(&logstr);
+               continue;
+           }
+           if (dp->d_flags & RT_DIR_REGION) {
+               fprintf(v5ofp, "put {%s} comb region yes tree {%s}\n",
+                       tclify_name(dp->d_namep),
+                       bu_vls_cstr(&logstr));
+           } else {
+               fprintf(v5ofp, "put {%s} comb region no tree {%s}\n",
+                       tclify_name(dp->d_namep),
+                       bu_vls_cstr(&logstr));
+           }
+           bu_vls_free(&logstr);
+       } else {
+           struct bu_vls logstr = BU_VLS_INIT_ZERO;
+
+           if ((dp->d_minor_type != ID_CONSTRAINT) && 
(intern.idb_meth->ft_get(&logstr, &intern, NULL) != 0)) {
+               rt_db_free_internal(&intern);
+               bu_log("Unable to export '%s', skipping: %s\n", dp->d_namep, 
bu_vls_cstr(&logstr));
+               bu_vls_free(&logstr);
+               continue;
+           }
+           fprintf(v5ofp, "put {%s} %s\n",
+                   tclify_name(dp->d_namep),
+                   bu_vls_cstr(&logstr));
+           bu_vls_free(&logstr);
+       }
+       avs = &intern.idb_avs;
+       if (avs->magic == BU_AVS_MAGIC && avs->count > 0) {
+           fprintf(v5ofp, "attr set {%s}", tclify_name(dp->d_namep));
+           for (unsigned int i = 0; i < avs->count; i++) {
+               if (strlen(avs->avp[i].name) <= 0) {
+                   continue;
+               }
+               fprintf(v5ofp, " {%s}", avs->avp[i].name);
+               fprintf(v5ofp, " {%s}", avs->avp[i].value);
+           }
+           fprintf(v5ofp, "\n");
+       }
+       rt_db_free_internal(&intern);
+    } FOR_ALL_DIRECTORY_END;
+
+    return 1;
+}
+
 // Local Variables:
 // tab-width: 8
 // mode: C++

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to