Revision: 75663
          http://sourceforge.net/p/brlcad/code/75663
Author:   starseeker
Date:     2020-05-01 21:39:07 +0000 (Fri, 01 May 2020)
Log Message:
-----------
Start roughing out a rework of the bot command to make it similar to the new 
form of the brep command.  Still needs a fair bit of testing - in particular 
the visualization for the bot checking code hasn't been tried, and the openvdb 
based rework needs to be enabled/tested after moving.  Goal is to bring 
organization to the bot subcommands and make it cleaner to add new 
functionality.  Not going to move any of the bot_* commands until the initial 
setup is complete and tested - right now just sticking to the commands that 
were already in bot.c

Modified Paths:
--------------
    brlcad/trunk/src/libged/CMakeLists.txt

Added Paths:
-----------
    brlcad/trunk/src/libged/bot/
    brlcad/trunk/src/libged/bot/bot.cpp
    brlcad/trunk/src/libged/bot/check.cpp
    brlcad/trunk/src/libged/bot/ged_bot.h
    brlcad/trunk/src/libged/bot/remesh.cpp

Removed Paths:
-------------
    brlcad/trunk/src/libged/bot.c
    brlcad/trunk/src/libged/bot_remesh.cpp

Modified: brlcad/trunk/src/libged/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/libged/CMakeLists.txt      2020-05-01 17:33:34 UTC (rev 
75662)
+++ brlcad/trunk/src/libged/CMakeLists.txt      2020-05-01 21:39:07 UTC (rev 
75663)
@@ -62,7 +62,9 @@
   bigE.c
   blast.c
   bo.c
-  bot.c
+  bot/bot.cpp
+  bot/check.cpp
+  bot/remesh.cpp
   bot_condense.c
   bot_decimate.c
   bot_dump.c
@@ -71,7 +73,6 @@
   bot_fuse.c
   bot_flip.c
   bot_merge.c
-  bot_remesh.cpp
   bot_smooth.c
   bot_split.c
   bot_sync.c

Added: brlcad/trunk/src/libged/bot/bot.cpp
===================================================================
--- brlcad/trunk/src/libged/bot/bot.cpp                         (rev 0)
+++ brlcad/trunk/src/libged/bot/bot.cpp 2020-05-01 21:39:07 UTC (rev 75663)
@@ -0,0 +1,387 @@
+/*                         B O T . C P P
+ * BRL-CAD
+ *
+ * Copyright (c) 2020 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+/** @file libged/bot/bot.cpp
+ *
+ * The LIBGED bot command.
+ *
+ */
+
+#include "common.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <list>
+#include <map>
+#include <queue>
+#include <set>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "bu/cmd.h"
+#include "bu/color.h"
+#include "bu/opt.h"
+#include "bg/chull.h"
+#include "bg/trimesh.h"
+#include "rt/geom.h"
+#include "wdb.h"
+
+#include "./ged_bot.h"
+
+int
+_bot_cmd_msgs(void *bs, int argc, const char **argv, const char *us, const 
char *ps)
+{
+    struct _ged_bot_info *gb = (struct _ged_bot_info *)bs;
+    if (argc == 2 && BU_STR_EQUAL(argv[1], HELPFLAG)) {
+       bu_vls_printf(gb->gedp->ged_result_str, "%s\n%s\n", us, ps);
+       return 1;
+    }
+    if (argc == 2 && BU_STR_EQUAL(argv[1], PURPOSEFLAG)) {
+       bu_vls_printf(gb->gedp->ged_result_str, "%s\n", ps);
+       return 1;
+    }
+    return 0;
+}
+
+extern "C" int
+_bot_cmd_get(void *bs, int argc, const char **argv)
+{
+    const char *usage_string = "bot [options] <objname> get 
<faces|minEdge|maxEdge|orientation|type|vertices>";
+    const char *purpose_string = "Report specific information about a BoT 
shape";
+    if (_bot_cmd_msgs(bs, argc, argv, usage_string, purpose_string)) {
+       return GED_OK;
+    }
+
+    struct _ged_bot_info *gb = (struct _ged_bot_info *)bs;
+
+    if (gb->intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
+       bu_vls_printf(gb->gedp->ged_result_str, ": object %s is not of type 
bot\n", gb->solid_name.c_str());
+       return GED_ERROR;
+    }
+
+    return GED_OK;
+}
+
+extern "C" int
+_bot_cmd_chull(void *bs, int argc, const char **argv)
+{
+    const char *usage_string = "bot [options] <objname> chull output_bot";
+    const char *purpose_string = "Generate the BoT's convex hull and store it 
in object <output_bot>";
+    if (_bot_cmd_msgs(bs, argc, argv, usage_string, purpose_string)) {
+       return GED_OK;
+    }
+
+    struct _ged_bot_info *gb = (struct _ged_bot_info *)bs;
+
+    if (gb->intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
+       bu_vls_printf(gb->gedp->ged_result_str, ": object %s is not of type 
bot\n", gb->solid_name.c_str());
+       return GED_ERROR;
+    }
+
+    struct rt_bot_internal *bot = (struct rt_bot_internal 
*)(gb->intern.idb_ptr);
+    int retval = 0;
+    int fc = 0;
+    int vc = 0;
+    point_t *vert_array;
+    int *faces;
+    unsigned char err = 0;
+
+    /* must be wanting help */
+    if (argc < 2) {
+       bu_vls_printf(gb->gedp->ged_result_str, "%s\n%s\n", usage_string, 
purpose_string);
+       return GED_ERROR;
+    }
+
+    retval = bg_3d_chull(&faces, &fc, &vert_array, &vc, (const point_t 
*)bot->vertices, (int)bot->num_vertices);
+
+    if (retval != 3) {
+       return GED_ERROR;
+    }
+
+    retval = mk_bot(gb->gedp->ged_wdbp, argv[1], RT_BOT_SOLID, RT_BOT_CCW, 
err, vc, fc, (fastf_t *)vert_array, faces, NULL, NULL);
+
+    bu_free(faces, "free faces");
+    bu_free(vert_array, "free verts");
+
+    if (retval) {
+       return GED_ERROR;
+    }
+
+    return GED_OK;
+}
+
+extern "C" int
+_bot_cmd_isect(void *bs, int argc, const char **argv)
+{
+    const char *usage_string = "bot [options] <objname> isect <objname2>";
+    const char *purpose_string = "(TODO) Test if BoT <objname> intersects with 
BoT <objname2>";
+    if (_bot_cmd_msgs(bs, argc, argv, usage_string, purpose_string)) {
+       return GED_OK;
+    }
+
+    struct _ged_bot_info *gb = (struct _ged_bot_info *)bs;
+
+    if (gb->intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
+       bu_vls_printf(gb->gedp->ged_result_str, ": object %s is not of type 
bot\n", gb->solid_name.c_str());
+       return GED_ERROR;
+    }
+
+
+    if (argc != 2) {
+        bu_vls_printf(gb->gedp->ged_result_str, "%s", usage_string);
+        return GED_ERROR;
+    }
+
+    struct rt_bot_internal *bot = (struct rt_bot_internal *)gb->intern.idb_ptr;
+    struct directory *bot_dp_2;
+    struct rt_db_internal intern_2;
+    struct rt_bot_internal *bot_2;
+
+    GED_DB_LOOKUP(gb->gedp, bot_dp_2, argv[2], LOOKUP_NOISY, GED_ERROR & 
GED_QUIET);
+    GED_DB_GET_INTERNAL(gb->gedp, &intern_2, bot_dp_2, bn_mat_identity, 
&rt_uniresource, GED_ERROR);
+
+    if (intern_2.idb_major_type != DB5_MAJORTYPE_BRLCAD || 
intern_2.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
+       bu_vls_printf(gb->gedp->ged_result_str, ": object %s is not of type 
bot\n", argv[2]);
+       rt_db_free_internal(&intern_2);
+       return GED_ERROR;
+    }
+    bot_2 = (struct rt_bot_internal *)intern_2.idb_ptr;
+
+    int fc_1 = (int)bot->num_faces;
+    int fc_2 = (int)bot_2->num_faces;
+    int vc_1 = (int)bot->num_vertices;
+    int vc_2 = (int)bot_2->num_vertices;
+    point_t *verts_1 = (point_t *)bot->vertices;
+    point_t *verts_2 = (point_t *)bot_2->vertices;
+    int *faces_1 = bot->faces;
+    int *faces_2 = bot_2->faces;
+
+    (void)bg_trimesh_isect(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+           faces_1, fc_1, verts_1, vc_1, faces_2, fc_2, verts_2, vc_2);
+
+    rt_db_free_internal(&intern_2);
+
+    return GED_OK;
+}
+
+
+extern "C" int
+_bot_cmd_help(void *bs, int argc, const char **argv)
+{
+    struct _ged_bot_info *gb = (struct _ged_bot_info *)bs;
+    if (!argc || !argv || BU_STR_EQUAL(argv[0], "help")) {
+       bu_vls_printf(gb->gedp->ged_result_str, "bot [options] <objname> 
subcommand [args]\n");
+       if (gb->gopts) {
+           char *option_help = bu_opt_describe(gb->gopts, NULL);
+           if (option_help) {
+               bu_vls_printf(gb->gedp->ged_result_str, "Options:\n%s\n", 
option_help);
+               bu_free(option_help, "help str");
+           }
+       }
+       bu_vls_printf(gb->gedp->ged_result_str, "Available subcommands:\n");
+       const struct bu_cmdtab *ctp = NULL;
+       int ret;
+       const char *helpflag[2];
+       helpflag[1] = PURPOSEFLAG;
+       size_t maxcmdlen = 0;
+       for (ctp = gb->cmds; ctp->ct_name != (char *)NULL; ctp++) {
+           maxcmdlen = (maxcmdlen > strlen(ctp->ct_name)) ? maxcmdlen : 
strlen(ctp->ct_name);
+       }
+       for (ctp = gb->cmds; ctp->ct_name != (char *)NULL; ctp++) {
+           bu_vls_printf(gb->gedp->ged_result_str, "  %s%*s", ctp->ct_name, 
(int)(maxcmdlen - strlen(ctp->ct_name)) + 2, " ");
+           if (!BU_STR_EQUAL(ctp->ct_name, "help")) {
+               helpflag[0] = ctp->ct_name;
+               bu_cmd(gb->cmds, 2, helpflag, 0, (void *)gb, &ret);
+           } else {
+               bu_vls_printf(gb->gedp->ged_result_str, "print help and 
exit\n");
+           }
+       }
+    } else {
+       int ret;
+       const char **helpargv = (const char **)bu_calloc(argc+1, sizeof(char 
*), "help argv");
+       helpargv[0] = argv[0];
+       helpargv[1] = HELPFLAG;
+       for (int i = 1; i < argc; i++) {
+           helpargv[i+1] = argv[i];
+       }
+       bu_cmd(gb->cmds, argc+1, helpargv, 0, (void *)gb, &ret);
+       bu_free(helpargv, "help argv");
+       return ret;
+    }
+
+    return GED_OK;
+}
+
+const struct bu_cmdtab _bot_cmds[] = {
+    { "get",        _bot_cmd_get},
+    { "check",      _bot_cmd_check},
+    { "chull",      _bot_cmd_chull},
+    { "isect",      _bot_cmd_isect},
+    { "remesh",     _bot_cmd_remesh},
+    { (char *)NULL,      NULL}
+};
+
+
+static int
+_ged_bot_opt_color(struct bu_vls *msg, size_t argc, const char **argv, void 
*set_c)
+{
+    struct bu_color **set_color = (struct bu_color **)set_c;
+    BU_GET(*set_color, struct bu_color);
+    return bu_opt_color(msg, argc, argv, (void *)(*set_color));
+}
+
+extern "C" int
+ged_bot(struct ged *gedp, int argc, const char *argv[])
+{
+    int help = 0;
+    struct _ged_bot_info gb;
+    gb.gedp = gedp;
+    gb.cmds = _bot_cmds;
+    gb.verbosity = 0;
+    struct bu_color *color = NULL;
+
+    // Sanity
+    if (UNLIKELY(!gedp || !argc || !argv)) {
+       return GED_ERROR;
+    }
+
+    // Clear results
+    bu_vls_trunc(gedp->ged_result_str, 0);
+
+    // We know we're the bot command - start processing args
+    argc--; argv++;
+
+    // See if we have any high level options set
+    struct bu_opt_desc d[5];
+    BU_OPT(d[0], "h", "help",    "",      NULL,                 &help,         
"Print help");
+    BU_OPT(d[1], "v", "verbose", "",      NULL,                 &gb.verbosity, 
"Verbose output");
+    BU_OPT(d[2], "V", "visualize", "",    NULL,                 &gb.visualize, 
"Visualize results");
+    BU_OPT(d[3], "C", "color",   "r/g/b", &_ged_bot_opt_color,  &color,        
"Set plotting color");
+    BU_OPT_NULL(d[4]);
+
+    gb.gopts = d;
+
+    if (!argc) {
+       _bot_cmd_help(&gb, 0, NULL);
+       return GED_OK;
+    }
+
+    // High level options are only defined prior to the subcommand
+    int cmd_pos = -1;
+    for (int i = 0; i < argc; i++) {
+       if (bu_cmd_valid(_bot_cmds, argv[i]) == BRLCAD_OK) {
+           cmd_pos = i;
+           break;
+       }
+    }
+
+    int acnt = (cmd_pos >= 0) ? cmd_pos : argc;
+
+    int opt_ret = bu_opt_parse(NULL, acnt, argv, d);
+
+    if (help) {
+       if (cmd_pos >= 0) {
+           argc = argc - cmd_pos;
+           argv = &argv[cmd_pos];
+           _bot_cmd_help(&gb, argc, argv);
+       } else {
+           _bot_cmd_help(&gb, 0, NULL);
+       }
+       return GED_OK;
+    }
+
+    // Must have a subcommand
+    if (cmd_pos == -1) {
+       bu_vls_printf(gedp->ged_result_str, ": no valid subcommand 
specified\n");
+       _bot_cmd_help(&gb, 0, NULL);
+       return GED_ERROR;
+    }
+
+
+    if (opt_ret != 1) {
+       bu_vls_printf(gedp->ged_result_str, ": no object specified before 
subcommand\n");
+       bu_vls_printf(gedp->ged_result_str, "bot [options] <objname> subcommand 
[args]\n");
+       if (color) {
+           BU_PUT(color, struct bu_color);
+       }
+       return GED_ERROR;
+    }
+
+    GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
+    GED_CHECK_DRAWABLE(gedp, GED_ERROR);
+    GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
+
+    gb.solid_name = std::string(argv[0]);
+    gb.dp = db_lookup(gedp->ged_wdbp->dbip, gb.solid_name.c_str(), 
LOOKUP_NOISY);
+    if (gb.dp == RT_DIR_NULL) {
+       bu_vls_printf(gedp->ged_result_str, ": %s is not a solid or does not 
exist in database", gb.solid_name.c_str());
+       if (color) {
+           BU_PUT(color, struct bu_color);
+       }
+       return GED_ERROR;
+    } else {
+       int real_flag = (gb.dp->d_addr == RT_DIR_PHONY_ADDR) ? 0 : 1;
+       if (!real_flag) {
+           /* solid doesn't exist */
+           bu_vls_printf(gedp->ged_result_str, ": %s is not a real solid", 
gb.solid_name.c_str());
+           if (color) {
+               BU_PUT(color, struct bu_color);
+           }
+           return GED_ERROR;
+       }
+    }
+
+    GED_DB_GET_INTERNAL(gedp, &gb.intern, gb.dp, bn_mat_identity, 
&rt_uniresource, GED_ERROR);
+    RT_CK_DB_INTERNAL(&gb.intern);
+
+    gb.vbp = rt_vlblock_init();
+    gb.color = color;
+
+    // Jump the processing past any options specified
+    argc = argc - cmd_pos;
+    argv = &argv[cmd_pos];
+
+    int ret;
+    if (bu_cmd(_bot_cmds, argc, argv, 0, (void *)&gb, &ret) == BRLCAD_OK) {
+       rt_db_free_internal(&gb.intern);
+       return ret;
+    } else {
+       bu_vls_printf(gedp->ged_result_str, "subcommand %s not defined", 
argv[0]);
+    }
+
+    bn_vlblock_free(gb.vbp);
+    gb.vbp = (struct bn_vlblock *)NULL;
+    rt_db_free_internal(&gb.intern);
+    return GED_ERROR;
+}
+
+// Local Variables:
+// tab-width: 8
+// mode: C++
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// c-file-style: "stroustrup"
+// End:
+// ex: shiftwidth=4 tabstop=8


Property changes on: brlcad/trunk/src/libged/bot/bot.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: brlcad/trunk/src/libged/bot/check.cpp
===================================================================
--- brlcad/trunk/src/libged/bot/check.cpp                               (rev 0)
+++ brlcad/trunk/src/libged/bot/check.cpp       2020-05-01 21:39:07 UTC (rev 
75663)
@@ -0,0 +1,745 @@
+#include "common.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "bu/cmd.h"
+#include "bu/opt.h"
+#include "bu/sort.h"
+#include "bg/chull.h"
+#include "bg/trimesh.h"
+#include "rt/geom.h"
+#include "wdb.h"
+#include "./ged_bot.h"
+
+
+struct _ged_bot_icheck {
+    struct _ged_bot_info *gb;
+    struct bu_vls *vls;
+    const struct bu_cmdtab *cmds;
+};
+
+/* for bsearch() */
+static int
+edge_compare(const void *a, const void *b)
+{
+    const int *edge_a = (int *)a;
+    const int *edge_b = (int *)b;
+    int diff = edge_a[0] - edge_b[0];
+    return diff ? diff : edge_a[1] - edge_b[1];
+}
+
+/* for bu_sort() */
+static int
+edge_cmp(const void *a, const void *b, void *UNUSED(context))
+{
+    return edge_compare(a, b);
+}
+
+static int
+is_edge_in_list(int edge[2], struct bg_trimesh_edges list)
+{
+    return (bsearch(edge, list.edges, list.count, sizeof(int) * 2, 
edge_compare) != NULL);
+}
+
+static int
+is_edge_in_lists(int edge[2], struct bg_trimesh_edges lists[], int num_lists)
+{
+    int i;
+    for (i = 0; i < num_lists; ++i) {
+       if (is_edge_in_list(edge, lists[i])) {
+           return 1;
+       }
+    }
+    return 0;
+}
+
+static struct bg_trimesh_edges*
+make_edges(int edge_count)
+{
+    struct bg_trimesh_edges *edges;
+    BU_ALLOC(edges, struct bg_trimesh_edges);
+    edges->count = 0;
+    edges->edges = (int *)bu_malloc(edge_count * 2 * sizeof(int), "make 
edges");
+    return edges;
+}
+
+static void
+copy_edge(int dst[2], int src[2])
+{
+    dst[0] = src[0];
+    dst[1] = src[1];
+}
+
+static void
+append_edge(struct bg_trimesh_edges *list, int edge[2])
+{
+    copy_edge(&list->edges[list->count * 2], edge);
+    ++(list->count);
+}
+
+static void
+append_edge_if_not_in_lists(struct bg_trimesh_edges *dst, int edge[2], struct 
bg_trimesh_edges lists[], int num_lists)
+{
+    if (!is_edge_in_lists(edge, lists, num_lists)) {
+       append_edge(dst, edge);
+    }
+}
+
+static struct bg_trimesh_edges*
+edges_not_in_lists(struct bg_trimesh_edges all, struct bg_trimesh_edges 
lists[], int num_lists)
+{
+    int i;
+    struct bg_trimesh_edges *remaining = make_edges(all.count);
+
+    for (i = 0; i < all.count; ++i) {
+       append_edge_if_not_in_lists(remaining, &all.edges[i * 2], lists, 
num_lists);
+    }
+    return remaining;
+}
+
+static struct bg_trimesh_edges*
+edges_from_half_edges(struct bg_trimesh_halfedge edge_list[], int num_edges)
+{
+    int i;
+    struct bg_trimesh_edges *edges = make_edges(num_edges);
+
+    for (i = 0; i < num_edges; ++i) {
+       int half_edge[2];
+       half_edge[0] = edge_list[i].va;
+       half_edge[1] = edge_list[i].vb;
+       append_edge_if_not_in_lists(edges, half_edge, edges, 1);
+    }
+    return edges;
+}
+
+static void
+standardize_edge(int edge[2])
+{
+    if (edge[1] < edge[0]) {
+       int tmp = edge[0];
+       edge[0] = edge[1];
+       edge[1] = tmp;
+    }
+}
+
+static void
+append_face_edges(struct bg_trimesh_edges *edges, int face[3])
+{
+    int i, edge[2];
+    for (i = 0; i < 3; ++i) {
+       edge[0] = face[i];
+       edge[1] = face[(i + 1) % 3];
+       standardize_edge(edge);
+       append_edge(edges, edge);
+    }
+}
+
+static struct bg_trimesh_edges*
+non_unique_face_edges(struct bg_trimesh_faces faces, struct rt_bot_internal 
*bot)
+{
+    int i;
+    struct bg_trimesh_edges *edges = make_edges(faces.count * 3);
+
+    for (i = 0; i < faces.count; ++i) {
+       append_face_edges(edges, &bot->faces[faces.faces[i] * 3]);
+    }
+    bu_sort(edges->edges, edges->count, sizeof(int) * 2, edge_cmp, NULL);
+    return edges;
+}
+
+static struct bg_trimesh_edges*
+face_edges(struct bg_trimesh_faces faces, struct rt_bot_internal *bot)
+{
+    int i;
+    struct bg_trimesh_edges *unique_edges = make_edges(faces.count * 3);
+    struct bg_trimesh_edges *all_edges = non_unique_face_edges(faces, bot);
+
+    for (i = 0; i < all_edges->count; ++i) {
+       append_edge_if_not_in_lists(unique_edges, &all_edges->edges[i * 2], 
unique_edges, 1);
+    }
+    bg_free_trimesh_edges(all_edges);
+    BU_FREE(all_edges, struct bg_trimesh_edges);
+
+    return unique_edges;
+}
+
+static struct bg_trimesh_faces*
+make_faces(int num_faces)
+{
+    struct bg_trimesh_faces *faces;
+    BU_ALLOC(faces, struct bg_trimesh_faces);
+
+    faces->count = 0;
+    faces->faces = (int *)bu_malloc(sizeof(int) * num_faces, "make faces");
+    return faces;
+}
+
+static struct bg_trimesh_faces*
+faces_from_bot(struct rt_bot_internal *bot)
+{
+    int i;
+    struct bg_trimesh_faces *faces = make_faces((int)bot->num_faces);
+    faces->count = (int)bot->num_faces;
+    for (i = 0; i < faces->count; ++i) {
+       faces->faces[i] = i;
+    }
+    return faces;
+}
+
+static struct bg_trimesh_edges*
+edges_from_bot(struct rt_bot_internal *bot)
+{
+    struct bg_trimesh_faces *faces = faces_from_bot(bot);
+    struct bg_trimesh_edges *edges = face_edges(*faces, bot);
+
+    bg_free_trimesh_faces(faces);
+    BU_FREE(faces, struct bg_trimesh_faces);
+
+    return edges;
+}
+
+static void
+draw_edges(struct bn_vlblock *vbp, struct rt_bot_internal *bot, int num_edges, 
int edges[], struct bu_color *color)
+{
+    struct bu_list *vhead;
+    point_t a,b;
+    unsigned char draw_color[3];
+    bu_color_to_rgb_chars(color, draw_color);
+
+    for (int curr_edge = 0; curr_edge < num_edges; curr_edge++) {
+       int p1 = edges[curr_edge*2];
+       int p2 = edges[curr_edge*2+1];
+       VSET(a, bot->vertices[p1*3], bot->vertices[p1*3+1], 
bot->vertices[p1*3+2]);
+       VSET(b, bot->vertices[p2*3], bot->vertices[p2*3+1], 
bot->vertices[p2*3+2]);
+       vhead = bn_vlblock_find(vbp, draw_color[0], draw_color[1], 
draw_color[2]);
+       BN_ADD_VLIST(vbp->free_vlist_hd, vhead, a, BN_VLIST_LINE_MOVE);
+       BN_ADD_VLIST(vbp->free_vlist_hd, vhead, b, BN_VLIST_LINE_DRAW);
+    }
+}
+
+
+static int
+_bot_check_msgs(void *bs, int argc, const char **argv, const char *us, const 
char *ps)
+{
+    struct _ged_bot_icheck *gb = (struct _ged_bot_icheck *)bs;
+    if (argc == 2 && BU_STR_EQUAL(argv[1], HELPFLAG)) {
+       bu_vls_printf(gb->vls, "%s\n%s\n", us, ps);
+       return 1;
+    }
+    if (argc == 2 && BU_STR_EQUAL(argv[1], PURPOSEFLAG)) {
+       bu_vls_printf(gb->vls, "%s\n", ps);
+       return 1;
+    }
+    return 0;
+}
+
+
+extern "C" int
+_bot_cmd_degen_faces(void *bs, int argc, const char **argv)
+{
+    const char *usage_string = "bot [options] <objname1> degen_faces";
+    const char *purpose_string = "Check BoT for degenerate faces";
+    if (_bot_check_msgs(bs, argc, argv, usage_string, purpose_string)) {
+       return GED_OK;
+    }
+
+    argc--;argv++;
+
+    struct _ged_bot_icheck *gib = (struct _ged_bot_icheck *)bs;
+
+    if (gib->gb->intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
+        bu_vls_printf(gib->gb->gedp->ged_result_str, ": object %s is not of 
type bot\n", gib->gb->solid_name.c_str());
+        return GED_ERROR;
+    }
+
+    struct rt_bot_internal *bot = (struct rt_bot_internal 
*)(gib->gb->intern.idb_ptr);
+    struct bu_color *color = gib->gb->color;
+    struct bn_vlblock *vbp = gib->gb->vbp;
+
+    struct bg_trimesh_faces degenerate = BG_TRIMESH_FACES_INIT_NULL;
+    struct bg_trimesh_edges *degen_edges, *all_edges, *other_edges;
+    int degenerate_faces = 0;
+    int num_faces = (int)bot->num_faces;
+
+    if (gib->gb->visualize) {
+       /* first pass - count errors */
+       degenerate_faces = bg_trimesh_degenerate_faces(num_faces, bot->faces, 
bg_trimesh_face_continue, NULL);
+
+       if (degenerate_faces) {
+           /* second pass - generate error faces array and draw it */
+           degenerate.count = 0;
+           degenerate.faces = (int *)bu_calloc(degenerate_faces, sizeof(int), 
"degenerate faces");
+           bg_trimesh_degenerate_faces(num_faces, bot->faces, 
bg_trimesh_face_gather, &degenerate);
+
+           degen_edges = face_edges(degenerate, bot);
+           bg_free_trimesh_faces(&degenerate);
+
+           all_edges = edges_from_bot(bot);
+           other_edges = edges_not_in_lists(*all_edges, degen_edges, 1);
+           bg_free_trimesh_edges(all_edges);
+           BU_FREE(all_edges, struct bg_trimesh_edges);
+
+           draw_edges(vbp, bot, degen_edges->count, degen_edges->edges, color);
+           struct bu_color red = BU_COLOR_INIT_ZERO;
+           bu_color_from_str(&red, "255/0/0");
+           draw_edges(vbp, bot, other_edges->count, other_edges->edges, &red);
+
+           bg_free_trimesh_edges(degen_edges);
+           BU_FREE(degen_edges, struct bg_trimesh_edges);
+           bg_free_trimesh_edges(other_edges);
+           BU_FREE(other_edges, struct bg_trimesh_edges);
+       }
+    } else {
+       /* fast path - exit on first error */
+       degenerate_faces = bg_trimesh_degenerate_faces(num_faces, bot->faces, 
bg_trimesh_face_exit, NULL);
+    }
+
+    bu_vls_printf(gib->vls, degenerate_faces ? "1" : "0");
+
+    if (gib->gb->visualize) {
+       struct bu_vls sname = BU_VLS_INIT_ZERO;
+       bu_vls_sprintf(&sname, "_%s_degen_faces", gib->gb->solid_name.c_str());
+       if (db_lookup(gib->gb->gedp->ged_wdbp->dbip, bu_vls_cstr(&sname), 
LOOKUP_QUIET) != RT_DIR_NULL) {
+           dl_erasePathFromDisplay(gib->gb->gedp->ged_gdp->gd_headDisplay, 
gib->gb->gedp->ged_wdbp->dbip, gib->gb->gedp->ged_free_vlist_callback, 
bu_vls_cstr(&sname), 1, gib->gb->gedp->freesolid);
+       }
+       _ged_cvt_vlblock_to_solids(gib->gb->gedp, vbp, bu_vls_cstr(&sname), 0);
+       bu_vls_free(&sname);
+    }
+
+    return GED_OK;
+}
+
+extern "C" int
+_bot_cmd_extra_edges(void *bs, int argc, const char **argv)
+{
+    const char *usage_string = "bot [options] <objname1> extra_edges";
+    const char *purpose_string = "Check BoT for edges which are not part of 
any triangle faces";
+    if (_bot_check_msgs(bs, argc, argv, usage_string, purpose_string)) {
+       return GED_OK;
+    }
+
+    argc--;argv++;
+
+    struct _ged_bot_icheck *gib = (struct _ged_bot_icheck *)bs;
+
+    if (gib->gb->intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
+        bu_vls_printf(gib->gb->gedp->ged_result_str, ": object %s is not of 
type bot\n", gib->gb->solid_name.c_str());
+        return GED_ERROR;
+    }
+
+    struct rt_bot_internal *bot = (struct rt_bot_internal 
*)(gib->gb->intern.idb_ptr);
+    struct bu_color *color = gib->gb->color;
+    struct bn_vlblock *vbp = gib->gb->vbp;
+
+
+    int num_faces, num_edges;
+    num_faces = (int)bot->num_faces;
+    num_edges = num_faces * 3;
+
+    /* generate half-edge list */
+    struct bg_trimesh_halfedge *edge_list;
+    if (!(edge_list = bg_trimesh_generate_edge_list(num_faces, bot->faces))) {
+       bu_vls_printf(gib->vls, "ERROR: failed to generate an edge list\n");
+       return GED_ERROR;
+    }
+
+    int extra_edges = 0;
+
+    if (gib->gb->visualize) {
+       /* first pass - count errors */
+       struct bg_trimesh_edges error_edges = BG_TRIMESH_EDGES_INIT_NULL;
+       struct bg_trimesh_edges *all_edges, *other_edges;
+
+       extra_edges = bg_trimesh_excess_edges(num_edges, edge_list, 
bg_trimesh_edge_continue, NULL);
+
+       if (extra_edges) {
+           /* second pass - generate error edge array and draw it */
+           error_edges.count = 0;
+           error_edges.edges = (int *)bu_calloc(extra_edges * 2, sizeof(int), 
"error edges");
+           extra_edges = bg_trimesh_excess_edges(num_edges, edge_list, 
bg_trimesh_edge_gather, &error_edges);
+
+           all_edges = edges_from_half_edges(edge_list, num_edges);
+           other_edges = edges_not_in_lists(*all_edges, &error_edges, 1);
+           bg_free_trimesh_edges(all_edges);
+           BU_FREE(all_edges, struct bg_trimesh_edges);
+
+           draw_edges(vbp, bot, error_edges.count, error_edges.edges, color);
+           struct bu_color red = BU_COLOR_INIT_ZERO;
+           bu_color_from_str(&red, "255/0/0");
+           draw_edges(vbp, bot, other_edges->count, other_edges->edges, &red);
+
+           bg_free_trimesh_edges(&error_edges);
+           bg_free_trimesh_edges(other_edges);
+           BU_FREE(other_edges, struct bg_trimesh_edges);
+       }
+    } else {
+       /* fast path - exit on first error */
+       extra_edges = bg_trimesh_excess_edges(num_edges, edge_list, 
bg_trimesh_edge_exit, NULL);
+    }
+
+    bu_free(edge_list, "edge list");
+
+    bu_vls_printf(gib->vls, extra_edges ? "1" : "0");
+
+    if (gib->gb->visualize) {
+       struct bu_vls sname = BU_VLS_INIT_ZERO;
+       bu_vls_sprintf(&sname, "_%s_extra_edges", gib->gb->solid_name.c_str());
+       if (db_lookup(gib->gb->gedp->ged_wdbp->dbip, bu_vls_cstr(&sname), 
LOOKUP_QUIET) != RT_DIR_NULL) {
+           dl_erasePathFromDisplay(gib->gb->gedp->ged_gdp->gd_headDisplay, 
gib->gb->gedp->ged_wdbp->dbip, gib->gb->gedp->ged_free_vlist_callback, 
bu_vls_cstr(&sname), 1, gib->gb->gedp->freesolid);
+       }
+       _ged_cvt_vlblock_to_solids(gib->gb->gedp, vbp, bu_vls_cstr(&sname), 0);
+       bu_vls_free(&sname);
+    }
+
+    return GED_OK;
+}
+
+extern "C" int
+_bot_cmd_flipped_edges(void *bs, int argc, const char **argv)
+{
+    const char *usage_string = "bot [options] <objname1> flipped_edges";
+    const char *purpose_string = "Check BoT for edges which are incorrectly 
oriented";
+    if (_bot_check_msgs(bs, argc, argv, usage_string, purpose_string)) {
+       return GED_OK;
+    }
+
+    argc--;argv++;
+
+    struct _ged_bot_icheck *gib = (struct _ged_bot_icheck *)bs;
+
+    if (gib->gb->intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
+        bu_vls_printf(gib->gb->gedp->ged_result_str, ": object %s is not of 
type bot\n", gib->gb->solid_name.c_str());
+        return GED_ERROR;
+    }
+
+    struct rt_bot_internal *bot = (struct rt_bot_internal 
*)(gib->gb->intern.idb_ptr);
+    struct bu_color *color = gib->gb->color;
+    struct bn_vlblock *vbp = gib->gb->vbp;
+
+
+    int num_faces, num_edges;
+    num_faces = (int)bot->num_faces;
+    num_edges = num_faces * 3;
+
+    /* generate half-edge list */
+    struct bg_trimesh_halfedge *edge_list;
+    if (!(edge_list = bg_trimesh_generate_edge_list(num_faces, bot->faces))) {
+       bu_vls_printf(gib->vls, "ERROR: failed to generate an edge list\n");
+       return GED_ERROR;
+    }
+
+    int flipped_edges = 0;
+
+    if (gib->gb->visualize) {
+       /* first pass - count errors */
+       struct bg_trimesh_edges error_edges = BG_TRIMESH_EDGES_INIT_NULL;
+       struct bg_trimesh_edges *all_edges, *other_edges;
+
+       flipped_edges = bg_trimesh_misoriented_edges(num_edges, edge_list, 
bg_trimesh_edge_continue, NULL);
+
+       if (flipped_edges) {
+           /* second pass - generate error edge array and draw it */
+           error_edges.count = 0;
+           error_edges.edges = (int *)bu_calloc(flipped_edges * 2, 
sizeof(int), "error edges");
+           flipped_edges = bg_trimesh_misoriented_edges(num_edges, edge_list, 
bg_trimesh_edge_gather, &error_edges);
+
+           all_edges = edges_from_half_edges(edge_list, num_edges);
+           other_edges = edges_not_in_lists(*all_edges, &error_edges, 1);
+           bg_free_trimesh_edges(all_edges);
+           BU_FREE(all_edges, struct bg_trimesh_edges);
+
+           draw_edges(vbp, bot, error_edges.count, error_edges.edges, color);
+           struct bu_color red = BU_COLOR_INIT_ZERO;
+           bu_color_from_str(&red, "255/0/0");
+           draw_edges(vbp, bot, other_edges->count, other_edges->edges, &red);
+
+           bg_free_trimesh_edges(&error_edges);
+           bg_free_trimesh_edges(other_edges);
+           BU_FREE(other_edges, struct bg_trimesh_edges);
+       }
+    } else {
+       /* fast path - exit on first error */
+       flipped_edges = bg_trimesh_excess_edges(num_edges, edge_list, 
bg_trimesh_edge_exit, NULL);
+    }
+
+    bu_free(edge_list, "edge list");
+
+    bu_vls_printf(gib->vls, flipped_edges ? "1" : "0");
+
+    if (gib->gb->visualize) {
+       struct bu_vls sname = BU_VLS_INIT_ZERO;
+       bu_vls_sprintf(&sname, "_%s_flipped_edges", 
gib->gb->solid_name.c_str());
+       if (db_lookup(gib->gb->gedp->ged_wdbp->dbip, bu_vls_cstr(&sname), 
LOOKUP_QUIET) != RT_DIR_NULL) {
+           dl_erasePathFromDisplay(gib->gb->gedp->ged_gdp->gd_headDisplay, 
gib->gb->gedp->ged_wdbp->dbip, gib->gb->gedp->ged_free_vlist_callback, 
bu_vls_cstr(&sname), 1, gib->gb->gedp->freesolid);
+       }
+       _ged_cvt_vlblock_to_solids(gib->gb->gedp, vbp, bu_vls_cstr(&sname), 0);
+       bu_vls_free(&sname);
+    }
+
+    return GED_OK;
+}
+
+extern "C" int
+_bot_cmd_open_edges(void *bs, int argc, const char **argv)
+{
+    const char *usage_string = "bot [options] <objname1> open_edges";
+    const char *purpose_string = "Check BoT for edges which are not connected 
to two triangle faces";
+    if (_bot_check_msgs(bs, argc, argv, usage_string, purpose_string)) {
+       return GED_OK;
+    }
+
+    argc--;argv++;
+
+    struct _ged_bot_icheck *gib = (struct _ged_bot_icheck *)bs;
+
+    if (gib->gb->intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
+        bu_vls_printf(gib->gb->gedp->ged_result_str, ": object %s is not of 
type bot\n", gib->gb->solid_name.c_str());
+        return GED_ERROR;
+    }
+
+    struct rt_bot_internal *bot = (struct rt_bot_internal 
*)(gib->gb->intern.idb_ptr);
+    struct bu_color *color = gib->gb->color;
+    struct bn_vlblock *vbp = gib->gb->vbp;
+
+
+    int num_faces, num_edges;
+    num_faces = (int)bot->num_faces;
+    num_edges = num_faces * 3;
+
+    /* generate half-edge list */
+    struct bg_trimesh_halfedge *edge_list;
+    if (!(edge_list = bg_trimesh_generate_edge_list(num_faces, bot->faces))) {
+       bu_vls_printf(gib->vls, "ERROR: failed to generate an edge list\n");
+       return GED_ERROR;
+    }
+
+    int open_edges = 0;
+
+    if (gib->gb->visualize) {
+       /* first pass - count errors */
+       struct bg_trimesh_edges error_edges = BG_TRIMESH_EDGES_INIT_NULL;
+       struct bg_trimesh_edges *all_edges, *other_edges;
+
+       open_edges = bg_trimesh_unmatched_edges(num_edges, edge_list, 
bg_trimesh_edge_continue, NULL);
+
+       if (open_edges) {
+           /* second pass - generate error edge array and draw it */
+           error_edges.count = 0;
+           error_edges.edges = (int *)bu_calloc(open_edges * 2, sizeof(int), 
"error edges");
+           open_edges = bg_trimesh_unmatched_edges(num_edges, edge_list, 
bg_trimesh_edge_gather, &error_edges);
+
+           all_edges = edges_from_half_edges(edge_list, num_edges);
+           other_edges = edges_not_in_lists(*all_edges, &error_edges, 1);
+           bg_free_trimesh_edges(all_edges);
+           BU_FREE(all_edges, struct bg_trimesh_edges);
+
+           draw_edges(vbp, bot, error_edges.count, error_edges.edges, color);
+           struct bu_color red = BU_COLOR_INIT_ZERO;
+           bu_color_from_str(&red, "255/0/0");
+           draw_edges(vbp, bot, other_edges->count, other_edges->edges, &red);
+
+           bg_free_trimesh_edges(&error_edges);
+           bg_free_trimesh_edges(other_edges);
+           BU_FREE(other_edges, struct bg_trimesh_edges);
+       }
+    } else {
+       /* fast path - exit on first error */
+       open_edges = bg_trimesh_excess_edges(num_edges, edge_list, 
bg_trimesh_edge_exit, NULL);
+    }
+
+    bu_free(edge_list, "edge list");
+
+    bu_vls_printf(gib->vls, open_edges ? "1" : "0");
+
+    if (gib->gb->visualize) {
+       struct bu_vls sname = BU_VLS_INIT_ZERO;
+       bu_vls_sprintf(&sname, "_%s_open_edges", gib->gb->solid_name.c_str());
+       if (db_lookup(gib->gb->gedp->ged_wdbp->dbip, bu_vls_cstr(&sname), 
LOOKUP_QUIET) != RT_DIR_NULL) {
+           dl_erasePathFromDisplay(gib->gb->gedp->ged_gdp->gd_headDisplay, 
gib->gb->gedp->ged_wdbp->dbip, gib->gb->gedp->ged_free_vlist_callback, 
bu_vls_cstr(&sname), 1, gib->gb->gedp->freesolid);
+       }
+       _ged_cvt_vlblock_to_solids(gib->gb->gedp, vbp, bu_vls_cstr(&sname), 0);
+       bu_vls_free(&sname);
+    }
+
+    return GED_OK;
+}
+
+
+extern "C" int
+_bot_cmd_solid(void *bs, int argc, const char **argv)
+{
+    const char *usage_string = "bot [options] <objname1> solid";
+    const char *purpose_string = "Check if BoT defines a topologically closed 
solid";
+    if (_bot_check_msgs(bs, argc, argv, usage_string, purpose_string)) {
+       return GED_OK;
+    }
+
+    argc--;argv++;
+
+    struct _ged_bot_icheck *gib = (struct _ged_bot_icheck *)bs;
+
+    if (gib->gb->intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
+        bu_vls_printf(gib->gb->gedp->ged_result_str, ": object %s is not of 
type bot\n", gib->gb->solid_name.c_str());
+        return GED_ERROR;
+    }
+
+    struct rt_bot_internal *bot = (struct rt_bot_internal 
*)(gib->gb->intern.idb_ptr);
+    struct bn_vlblock *vbp = gib->gb->vbp;
+    struct bg_trimesh_solid_errors errors = BG_TRIMESH_SOLID_ERRORS_INIT_NULL;
+    int not_solid;
+
+    if (bot->mode == RT_BOT_PLATE || bot->mode == RT_BOT_PLATE_NOCOS) {
+       bu_vls_printf(gib->vls, "1");
+       return GED_OK;
+    }
+
+    int num_vertices = (int)bot->num_vertices;
+    int num_faces = (int)bot->num_faces;
+
+    not_solid = bg_trimesh_solid2(num_vertices, num_faces, bot->vertices, 
bot->faces, gib->gb->visualize ? &errors : NULL);
+    bu_vls_printf(gib->vls, "%d", (not_solid) ? 0 : 1);
+
+    if (not_solid && gib->gb->visualize) {
+       struct bg_trimesh_edges *degen_edges = NULL, *all_edges, *other_edges;
+       struct bg_trimesh_edges error_lists[4];
+       int num_lists = 0;
+
+       error_lists[num_lists++] = errors.unmatched;
+       error_lists[num_lists++] = errors.misoriented;
+       error_lists[num_lists++] = errors.excess;
+       if (errors.degenerate.count > 0) {
+           degen_edges = face_edges(errors.degenerate, bot);
+           error_lists[num_lists++] = *degen_edges;
+       }
+
+       all_edges = edges_from_bot(bot);
+       other_edges = edges_not_in_lists(*all_edges, error_lists, num_lists);
+       bg_free_trimesh_edges(all_edges);
+       BU_FREE(all_edges, struct bg_trimesh_edges);
+
+       struct bu_color red = BU_COLOR_INIT_ZERO;
+       bu_color_from_str(&red, "255/0/0");
+       struct bu_color yellow = BU_COLOR_INIT_ZERO;
+       bu_color_from_str(&yellow, "255/255/0");
+       struct bu_color orange = BU_COLOR_INIT_ZERO;
+       bu_color_from_str(&orange, "255/128/0");
+       struct bu_color purple = BU_COLOR_INIT_ZERO;
+       bu_color_from_str(&purple, "255/0/255");
+
+       draw_edges(vbp, bot, other_edges->count, other_edges->edges, &red);
+       draw_edges(vbp, bot, errors.unmatched.count, errors.unmatched.edges, 
&yellow);
+       draw_edges(vbp, bot, errors.misoriented.count, 
errors.misoriented.edges, &orange);
+       draw_edges(vbp, bot, errors.excess.count, errors.excess.edges, &purple);
+
+       if (errors.degenerate.count > 0) {
+           struct bu_color blue = BU_COLOR_INIT_ZERO;
+           bu_color_from_str(&blue, "0/0/255");
+           draw_edges(vbp, bot, degen_edges->count, degen_edges->edges, &blue);
+
+           bg_free_trimesh_edges(degen_edges);
+           BU_FREE(degen_edges, struct bg_trimesh_edges);
+       }
+       bg_free_trimesh_edges(other_edges);
+       BU_FREE(other_edges, struct bg_trimesh_edges);
+       bg_free_trimesh_solid_errors(&errors);
+
+       struct bu_vls sname = BU_VLS_INIT_ZERO;
+       bu_vls_sprintf(&sname, "_%s_not_solid", gib->gb->solid_name.c_str());
+       if (db_lookup(gib->gb->gedp->ged_wdbp->dbip, bu_vls_cstr(&sname), 
LOOKUP_QUIET) != RT_DIR_NULL) {
+           dl_erasePathFromDisplay(gib->gb->gedp->ged_gdp->gd_headDisplay, 
gib->gb->gedp->ged_wdbp->dbip, gib->gb->gedp->ged_free_vlist_callback, 
bu_vls_cstr(&sname), 1, gib->gb->gedp->freesolid);
+       }
+       _ged_cvt_vlblock_to_solids(gib->gb->gedp, vbp, bu_vls_cstr(&sname), 0);
+       bu_vls_free(&sname);
+    }
+
+    return GED_OK;
+}
+
+static void
+_bot_check_help(struct _ged_bot_icheck *bs, int argc, const char **argv)
+{
+    struct _ged_bot_icheck *gb = (struct _ged_bot_icheck *)bs;
+    if (!argc || !argv) {
+       bu_vls_printf(gb->vls, "bot [options] <objname> check [subcommand]\n");
+       bu_vls_printf(gb->vls, "Available subcommands:\n");
+       const struct bu_cmdtab *ctp = NULL;
+       int ret;
+       const char *helpflag[2];
+       helpflag[1] = PURPOSEFLAG;
+       size_t maxcmdlen = 0;
+       for (ctp = gb->cmds; ctp->ct_name != (char *)NULL; ctp++) {
+           maxcmdlen = (maxcmdlen > strlen(ctp->ct_name)) ? maxcmdlen : 
strlen(ctp->ct_name);
+       }
+       for (ctp = gb->cmds; ctp->ct_name != (char *)NULL; ctp++) {
+           bu_vls_printf(gb->vls, "  %s%*s", ctp->ct_name, (int)(maxcmdlen - 
strlen(ctp->ct_name)) + 2, " ");
+           helpflag[0] = ctp->ct_name;
+           bu_cmd(gb->cmds, 2, helpflag, 0, (void *)gb, &ret);
+       }
+    } else {
+       int ret;
+       const char *helpflag[2];
+       helpflag[0] = argv[0];
+       helpflag[1] = HELPFLAG;
+       bu_cmd(gb->cmds, 2, helpflag, 0, (void *)gb, &ret);
+    }
+}
+
+const struct bu_cmdtab _bot_check_cmds[] = {
+    { "degen_faces",   _bot_cmd_degen_faces},
+    { "extra_edges",   _bot_cmd_extra_edges},
+    { "flipped_edges", _bot_cmd_flipped_edges},
+    { "open_edges",    _bot_cmd_open_edges},
+    { "solid",         _bot_cmd_solid},
+    { (char *)NULL,      NULL}
+};
+
+int
+_bot_cmd_check(void *bs, int argc, const char **argv)
+{
+    struct _ged_bot_info *gb = (struct _ged_bot_info *)bs;
+    struct _ged_bot_icheck gib;
+    gib.gb = gb;
+    gib.vls = gb->gedp->ged_result_str;
+    gib.cmds = _bot_check_cmds;
+
+
+    if (!argc) {
+       _bot_check_help(&gib, 0, NULL);
+       return GED_OK;
+    }
+
+    if (argc > 1 && BU_STR_EQUAL(argv[1], HELPFLAG)) {
+       argc--;argv++;
+       argc--;argv++;
+       _bot_check_help(&gib, argc, argv);
+       return GED_OK;
+    }
+
+    argc--; argv++;
+
+    // Must have valid subcommand to process
+    if (bu_cmd_valid(_bot_check_cmds, argv[0]) != BRLCAD_OK) {
+       bu_vls_printf(gib.vls, "invalid subcommand \"%s\" specified\n", 
argv[0]);
+       _bot_check_help(&gib, 0, NULL);
+       return GED_ERROR;
+    }
+
+    int ret;
+    if (bu_cmd(_bot_check_cmds, argc, argv, 0, (void *)&gib, &ret) == 
BRLCAD_OK) {
+       return ret;
+    }
+    return GED_ERROR;
+}
+
+
+
+// Local Variables:
+// tab-width: 8
+// mode: C++
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// c-file-style: "stroustrup"
+// End:
+// ex: shiftwidth=4 tabstop=8


Property changes on: brlcad/trunk/src/libged/bot/check.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: brlcad/trunk/src/libged/bot/ged_bot.h
===================================================================
--- brlcad/trunk/src/libged/bot/ged_bot.h                               (rev 0)
+++ brlcad/trunk/src/libged/bot/ged_bot.h       2020-05-01 21:39:07 UTC (rev 
75663)
@@ -0,0 +1,86 @@
+/*                    G E D _ B O T . H
+ * BRL-CAD
+ *
+ * Copyright (c) 2008-2020 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+/** @file ged_bot.h
+ *
+ * Private header for libged bot cmd.
+ *
+ */
+
+#ifndef LIBGED_BREP_GED_PRIVATE_H
+#define LIBGED_BREP_GED_PRIVATE_H
+
+#include "common.h"
+
+#include <set>
+#include <string>
+#include <time.h>
+
+#include "bu/opt.h"
+#include "bn/plot3.h"
+#include "bu/color.h"
+#include "rt/db4.h"
+#include "raytrace.h"
+#include "rt/geom.h"
+#include "ged.h"
+
+__BEGIN_DECLS
+
+#define HELPFLAG "--print-help"
+#define PURPOSEFLAG "--print-purpose"
+
+struct _ged_bot_info {
+    struct ged *gedp = NULL;
+    struct rt_db_internal intern;
+    struct directory *dp = NULL;
+    struct bn_vlblock *vbp = NULL;
+    struct bu_color *color = NULL;
+    int verbosity;
+    int visualize;
+    std::string solid_name;
+    const struct bu_cmdtab *cmds = NULL;
+    struct bu_opt_desc *gopts = NULL;
+};
+
+/* defined in draw.c */
+extern void _ged_cvt_vlblock_to_solids(struct ged *gedp,
+                                      struct bn_vlblock *vbp,
+                                      const char *name,
+                                      int copy);
+
+int _bot_cmd_msgs(void *bs, int argc, const char **argv, const char *us, const 
char *ps);
+
+int _bot_cmd_check(void *bs, int argc, const char **argv);
+
+int _bot_cmd_remesh(void *bs, int argc, const char **argv);
+
+__END_DECLS
+
+#endif /* LIBGED_BREP_GED_PRIVATE_H */
+
+/** @} */
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */


Property changes on: brlcad/trunk/src/libged/bot/ged_bot.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Copied: brlcad/trunk/src/libged/bot/remesh.cpp (from rev 75662, 
brlcad/trunk/src/libged/bot_remesh.cpp)
===================================================================
--- brlcad/trunk/src/libged/bot/remesh.cpp                              (rev 0)
+++ brlcad/trunk/src/libged/bot/remesh.cpp      2020-05-01 21:39:07 UTC (rev 
75663)
@@ -0,0 +1,270 @@
+/*                     B O T _ R E M E S H . C P P
+ * BRL-CAD
+ *
+ * Copyright (c) 2019-2020 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+/** @file libged/bot_remesh.cpp
+ *
+ * The bot "remesh" sub-command.
+ *
+ */
+
+#include "common.h"
+
+#ifdef OPENVDB_ABI_VERSION_NUMBER
+#  include <openvdb/openvdb.h>
+#  include <openvdb/tools/VolumeToMesh.h>
+#  include <openvdb/tools/MeshToVolume.h>
+#endif /* OPENVDB_ABI_VERSION_NUMBER */
+
+#include "vmath.h"
+#include "bu/str.h"
+#include "rt/db5.h"
+#include "rt/db_internal.h"
+#include "rt/db_io.h"
+#include "rt/geom.h"
+#include "rt/wdb.h"
+#include "ged/commands.h"
+#include "ged/database.h"
+#include "ged/objects.h"
+#include "./ged_bot.h"
+
+
+#ifdef OPENVDB_ABI_VERSION_NUMBER
+
+struct botDataAdapter {
+    struct rt_bot_internal *bot;
+
+    size_t polygonCount() const {
+       return bot->num_faces;
+    };
+    size_t pointCount() const {
+       return bot->num_vertices;
+    };
+    size_t vertexCount(size_t) const {
+       return 3;
+    };
+    void getIndexSpacePoint(size_t n, size_t v, openvdb::Vec3d& pos) const {
+       int idx = bot->faces[(n*3)+v];
+       pos[X] = bot->vertices[(idx*3)+X];
+       pos[Y] = bot->vertices[(idx*3)+Y];
+       pos[Z] = bot->vertices[(idx*3)+Z];
+       return;
+    };
+
+    /* constructor */
+    botDataAdapter(struct rt_bot_internal *bip) : bot(bip) {}
+};
+
+
+static bool
+bot_remesh(struct ged *UNUSED(gedp), struct rt_bot_internal *bot, double 
voxelSize)
+{
+    const float exteriorBandWidth = 10.0;
+    const float interiorBandWidth = std::numeric_limits<float>::max();
+
+    struct botDataAdapter bda(bot);
+
+    openvdb::initialize();
+
+    bu_log("...voxelizing");
+
+    openvdb::math::Transform::Ptr xform = 
openvdb::math::Transform::createLinearTransform(voxelSize);
+    openvdb::FloatGrid::Ptr bot2vol = 
openvdb::tools::meshToVolume<openvdb::FloatGrid, botDataAdapter>(bda, *xform, 
exteriorBandWidth, interiorBandWidth);
+
+#if 0
+    openvdb::io::File file("mesh.vdb");
+    openvdb::GridPtrVec grids;
+    grids.push_back(bot2vol);
+    file.write(grids);
+    file.close();
+    return false;
+#endif
+
+    bu_log("...devoxelizing");
+
+    std::vector<openvdb::Vec3s> points;
+    std::vector<openvdb::Vec3I> triangles;
+    std::vector<openvdb::Vec4I> quadrilaterals;
+    openvdb::tools::volumeToMesh<openvdb::FloatGrid>(*bot2vol, points, 
triangles, quadrilaterals);
+
+    bu_log("...storing");
+
+    if (bot->vertices) {
+       bu_free(bot->vertices, "vertices");
+       bot->num_vertices = 0;
+    }
+    if (bot->faces) {
+       bu_free(bot->faces, "faces");
+       bot->num_faces = 0;
+    }
+    if (bot->normals) {
+       bu_free(bot->normals, "normals");
+    }
+    if (bot->face_normals) {
+       bu_free(bot->face_normals, "face normals");
+    }
+
+    bot->num_vertices = points.size();
+    bot->vertices = (fastf_t *)bu_malloc(bot->num_vertices * 
ELEMENTS_PER_POINT * sizeof(fastf_t), "vertices");
+    for (size_t i = 0; i < points.size(); i++) {
+       bot->vertices[(i*3)+X] = points[i].x();
+       bot->vertices[(i*3)+Y] = points[i].y();
+       bot->vertices[(i*3)+Z] = points[i].z();
+    }
+    bot->num_faces = triangles.size() + (quadrilaterals.size() * 2);
+    bot->faces = (int *)bu_malloc(bot->num_faces * 3 * sizeof(int), 
"triangles");
+    for (size_t i = 0; i < triangles.size(); i++) {
+       bot->faces[(i*3)+X] = triangles[i].x();
+       bot->faces[(i*3)+Y] = triangles[i].y();
+       bot->faces[(i*3)+Z] = triangles[i].z();
+    }
+    size_t ntri = triangles.size();
+    for (size_t i = 0; i < quadrilaterals.size(); i++) {
+       bot->faces[((ntri+i)*3)+X] = quadrilaterals[i][0];
+       bot->faces[((ntri+i)*3)+Y] = quadrilaterals[i][1];
+       bot->faces[((ntri+i)*3)+Z] = quadrilaterals[i][2];
+
+       bot->faces[((ntri+i+1)*3)+X] = quadrilaterals[i][0];
+       bot->faces[((ntri+i+1)*3)+Y] = quadrilaterals[i][2];
+       bot->faces[((ntri+i+1)*3)+Z] = quadrilaterals[i][3];
+    }
+
+    bu_log("...done!\n");
+
+    return (points.size() > 0);
+}
+
+#else /* OPENVDB_ABI_VERSION_NUMBER */
+
+static bool
+bot_remesh(struct ged *gedp, struct rt_bot_internal *UNUSED(bot), double 
UNUSED(voxelSize))
+{
+    bu_vls_printf(gedp->ged_result_str,
+                 "WARNING: BoT remeshing is unavailable.\n"
+                 "BRL-CAD needs to be compiled with OpenVDB support.\n"
+                 "(cmake -DBRLCAD_ENABLE_OPENVDB=ON)\n");
+    return false;
+}
+
+#endif /* OPENVDB_ABI_VERSION_NUMBER */
+
+
+
+
+extern "C" int
+_bot_cmd_remesh(void *bs, int argc, const char **argv)
+{
+    const char *usage_string = "bot [options] <objname> remesh [output_bot]";
+    const char *purpose_string = "Store a remeshed version of the BoT in 
object <output_bot>";
+    if (_bot_cmd_msgs(bs, argc, argv, usage_string, purpose_string)) {
+       return GED_OK;
+    }
+
+    struct _ged_bot_info *gb = (struct _ged_bot_info *)bs;
+
+    struct ged *gedp = gb->gedp;
+
+    if (gb->intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
+       bu_vls_printf(gb->gedp->ged_result_str, ": object %s is not of type 
bot\n", gb->solid_name.c_str());
+       return GED_ERROR;
+    }
+
+    const char *input_bot_name = gb->dp->d_namep;
+    const char *output_bot_name;
+    struct directory *dp_input;
+    struct directory *dp_output;
+    struct rt_bot_internal *input_bot;
+
+    GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
+    GED_CHECK_READ_ONLY(gedp, GED_ERROR);
+    GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
+
+    dp_input = dp_output = RT_DIR_NULL;
+
+    /* initialize result */
+    bu_vls_trunc(gedp->ged_result_str, 0);
+
+    /* must be wanting help */
+    if (argc == 1) {
+       bu_vls_printf(gedp->ged_result_str, "%s\n%s", usage_string, 
purpose_string);
+       return GED_HELP;
+    }
+
+    /* check that we are using a version 5 database */
+    if (db_version(gedp->ged_wdbp->dbip) < 5) {
+       bu_vls_printf(gedp->ged_result_str,
+                     "ERROR: Unable to remesh the current (v%d) database.\n"
+                     "Use \"dbupgrade\" to upgrade this database to the 
current version.\n",
+                     db_version(gedp->ged_wdbp->dbip));
+       return GED_ERROR;
+    }
+
+    if (argc > 3) {
+       bu_vls_printf(gedp->ged_result_str, "ERROR: unexpected arguments 
encountered\n");
+       bu_vls_printf(gedp->ged_result_str, "%s\n%s", usage_string, 
purpose_string);
+       return GED_ERROR;
+    }
+
+    output_bot_name = input_bot_name;
+    if (argc > 1)
+       output_bot_name = (char *)argv[1];
+
+    if (!BU_STR_EQUAL(input_bot_name, output_bot_name)) {
+       GED_CHECK_EXISTS(gedp, output_bot_name, LOOKUP_QUIET, GED_ERROR);
+    }
+
+    if (gb->intern.idb_major_type != DB5_MAJORTYPE_BRLCAD || 
gb->intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
+       bu_vls_printf(gedp->ged_result_str, "%s is not a BOT primitive\n", 
input_bot_name);
+       return GED_ERROR;
+    }
+
+    input_bot = (struct rt_bot_internal *)gb->intern.idb_ptr;
+    RT_BOT_CK_MAGIC(input_bot);
+
+    bu_log("INPUT BoT has %zu vertices and %zu faces\n", 
input_bot->num_vertices, input_bot->num_faces);
+
+    /* TODO: stash a backup if overwriting the original */
+
+    bool ok = bot_remesh(gedp, input_bot, 50);
+    if (!ok) {
+       return GED_ERROR;
+    }
+
+    bu_log("OUTPUT BoT has %zu vertices and %zu faces\n", 
input_bot->num_vertices, input_bot->num_faces);
+
+    if (BU_STR_EQUAL(input_bot_name, output_bot_name)) {
+       dp_output = dp_input;
+    } else {
+       GED_DB_DIRADD(gedp, dp_output, output_bot_name, RT_DIR_PHONY_ADDR, 0, 
RT_DIR_SOLID, (void *)&gb->intern.idb_type, GED_ERROR);
+    }
+
+    GED_DB_PUT_INTERNAL(gedp, dp_output, &gb->intern, 
gedp->ged_wdbp->wdb_resp, GED_ERROR);
+
+    return GED_OK;
+}
+
+
+/*
+ * Local Variables:
+ * tab-width: 8
+ * mode: C
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */

Deleted: brlcad/trunk/src/libged/bot.c
===================================================================
--- brlcad/trunk/src/libged/bot.c       2020-05-01 17:33:34 UTC (rev 75662)
+++ brlcad/trunk/src/libged/bot.c       2020-05-01 21:39:07 UTC (rev 75663)
@@ -1,709 +0,0 @@
-/*                         B O T . C
- * BRL-CAD
- *
- * Copyright (c) 2008-2020 United States Government as represented by
- * the U.S. Army Research Laboratory.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this file; see the file named COPYING for more
- * information.
- */
-/** @file libged/bot.c
- *
- * Bot command for simple bot primitive operations.
- *
- */
-
-#include "common.h"
-
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-
-#include "bu/opt.h"
-#include "bu/sort.h"
-#include "bg/chull.h"
-#include "bg/trimesh.h"
-#include "rt/geom.h"
-#include "wdb.h"
-#include "./ged_private.h"
-
-
-HIDDEN void
-_bot_show_help(struct ged *gedp, struct bu_opt_desc *d)
-{
-    struct bu_vls str = BU_VLS_INIT_ZERO;
-    char *option_help;
-
-    bu_vls_sprintf(&str, "Usage: bot [options] [subcommand] [subcommand 
arguments]\n\n");
-
-    if ((option_help = bu_opt_describe(d, NULL))) {
-       bu_vls_printf(&str, "Options:\n%s\n", option_help);
-       bu_free(option_help, "help str");
-    }
-    bu_vls_printf(&str, "Subcommands:\n\n");
-    bu_vls_printf(&str, "  get   
(faces|minEdge|maxEdge|orientation|type|vertices) <bot>\n");
-    bu_vls_printf(&str, "    - Get specific BoT information.\n");
-    bu_vls_printf(&str, "  check 
(solid|degen_faces|open_edges|extra_edges|flipped_edges) <bot>\n");
-    bu_vls_printf(&str, "    - Check the BoT for problems (see bot_check man 
page).\n");
-    bu_vls_printf(&str, "  chull <bot> <output_bot>\n");
-    bu_vls_printf(&str, "    - Store the BoT's convex hull in 
<output_bot>.\n");
-    bu_vls_printf(&str, "  remesh <bot> <output_bot>\n");
-    bu_vls_printf(&str, "    - Store a remeshed version of <bot> in 
<output_bot>.\n");
-/*
-  TODO: document 'isect'
-    bu_vls_printf(&str, "  isect <bot1> <bot2>\n");
-    bu_vls_printf(&str, "    - intersection of <bot1> and <bot2>.\n");
-
-  TODO: add/merge other bot_* commands as subcommands
-*/
-    bu_vls_printf(&str, "\n");
-
-    bu_vls_vlscat(gedp->ged_result_str, &str);
-    bu_vls_free(&str);
-}
-
-/* for bsearch() */
-HIDDEN int
-edge_compare(const void *a, const void *b)
-{
-    const int *edge_a = (int *)a;
-    const int *edge_b = (int *)b;
-    int diff = edge_a[0] - edge_b[0];
-    return diff ? diff : edge_a[1] - edge_b[1];
-}
-
-/* for bu_sort() */
-HIDDEN int
-edge_cmp(const void *a, const void *b, void *UNUSED(context))
-{
-    return edge_compare(a, b);
-}
-
-HIDDEN int
-is_edge_in_list(int edge[2], struct bg_trimesh_edges list)
-{
-    return (bsearch(edge, list.edges, list.count, sizeof(int) * 2, 
edge_compare) != NULL);
-}
-
-HIDDEN int
- is_edge_in_lists(int edge[2], struct bg_trimesh_edges lists[], int num_lists)
-{
-    int i;
-    for (i = 0; i < num_lists; ++i) {
-       if (is_edge_in_list(edge, lists[i])) {
-           return 1;
-       }
-    }
-    return 0;
-}
-
-HIDDEN struct bg_trimesh_edges*
-make_edges(int edge_count)
-{
-    struct bg_trimesh_edges *edges;
-    BU_ALLOC(edges, struct bg_trimesh_edges);
-    edges->count = 0;
-    edges->edges = (int *)bu_malloc(edge_count * 2 * sizeof(int), "make 
edges");
-    return edges;
-}
-
-HIDDEN void
-copy_edge(int dst[2], int src[2])
-{
-    dst[0] = src[0];
-    dst[1] = src[1];
-}
-
-HIDDEN void
-append_edge(struct bg_trimesh_edges *list, int edge[2])
-{
-    copy_edge(&list->edges[list->count * 2], edge);
-    ++(list->count);
-}
-
-HIDDEN void
-append_edge_if_not_in_lists(struct bg_trimesh_edges *dst, int edge[2], struct 
bg_trimesh_edges lists[], int num_lists)
-{
-    if (!is_edge_in_lists(edge, lists, num_lists)) {
-       append_edge(dst, edge);
-    }
-}
-
-HIDDEN struct bg_trimesh_edges*
-edges_not_in_lists(struct bg_trimesh_edges all, struct bg_trimesh_edges 
lists[], int num_lists)
-{
-    int i;
-    struct bg_trimesh_edges *remaining = make_edges(all.count);
-
-    for (i = 0; i < all.count; ++i) {
-       append_edge_if_not_in_lists(remaining, &all.edges[i * 2], lists, 
num_lists);
-    }
-    return remaining;
-}
-
-HIDDEN struct bg_trimesh_edges*
-edges_from_half_edges(struct bg_trimesh_halfedge edge_list[], int num_edges)
-{
-    int i;
-    struct bg_trimesh_edges *edges = make_edges(num_edges);
-
-    for (i = 0; i < num_edges; ++i) {
-       int half_edge[2];
-       half_edge[0] = edge_list[i].va;
-       half_edge[1] = edge_list[i].vb;
-       append_edge_if_not_in_lists(edges, half_edge, edges, 1);
-    }
-    return edges;
-}
-
-HIDDEN void
-standardize_edge(int edge[2])
-{
-    if (edge[1] < edge[0]) {
-       int tmp = edge[0];
-       edge[0] = edge[1];
-       edge[1] = tmp;
-    }
-}
-
-HIDDEN void
-append_face_edges(struct bg_trimesh_edges *edges, int face[3])
-{
-    int i, edge[2];
-    for (i = 0; i < 3; ++i) {
-       edge[0] = face[i];
-       edge[1] = face[(i + 1) % 3];
-       standardize_edge(edge);
-       append_edge(edges, edge);
-    }
-}
-
-HIDDEN struct bg_trimesh_edges*
-non_unique_face_edges(struct bg_trimesh_faces faces, struct rt_bot_internal 
*bot)
-{
-    int i;
-    struct bg_trimesh_edges *edges = make_edges(faces.count * 3);
-
-    for (i = 0; i < faces.count; ++i) {
-       append_face_edges(edges, &bot->faces[faces.faces[i] * 3]);
-    }
-    bu_sort(edges->edges, edges->count, sizeof(int) * 2, edge_cmp, NULL);
-    return edges;
-}
-
-HIDDEN struct bg_trimesh_edges*
-face_edges(struct bg_trimesh_faces faces, struct rt_bot_internal *bot)
-{
-    int i;
-    struct bg_trimesh_edges *unique_edges = make_edges(faces.count * 3);
-    struct bg_trimesh_edges *all_edges = non_unique_face_edges(faces, bot);
-
-    for (i = 0; i < all_edges->count; ++i) {
-       append_edge_if_not_in_lists(unique_edges, &all_edges->edges[i * 2], 
unique_edges, 1);
-    }
-    bg_free_trimesh_edges(all_edges);
-    BU_FREE(all_edges, struct bg_trimesh_edges);
-
-    return unique_edges;
-}
-
-HIDDEN struct bg_trimesh_faces*
-make_faces(int num_faces)
-{
-    struct bg_trimesh_faces *faces;
-    BU_ALLOC(faces, struct bg_trimesh_faces);
-
-    faces->count = 0;
-    faces->faces = (int *)bu_malloc(sizeof(int) * num_faces, "make faces");
-    return faces;
-}
-
-HIDDEN struct bg_trimesh_faces*
-faces_from_bot(struct rt_bot_internal *bot)
-{
-    int i;
-    struct bg_trimesh_faces *faces = make_faces((int)bot->num_faces);
-    faces->count = (int)bot->num_faces;
-    for (i = 0; i < faces->count; ++i) {
-       faces->faces[i] = i;
-    }
-    return faces;
-}
-
-HIDDEN struct bg_trimesh_edges*
-edges_from_bot(struct rt_bot_internal *bot)
-{
-    struct bg_trimesh_faces *faces = faces_from_bot(bot);
-    struct bg_trimesh_edges *edges = face_edges(*faces, bot);
-
-    bg_free_trimesh_faces(faces);
-    BU_FREE(faces, struct bg_trimesh_faces);
-
-    return edges;
-}
-
-HIDDEN void
-draw_edges(struct ged *gedp, struct rt_bot_internal *bot, int num_edges, int 
edges[], int draw_color[3], const char *draw_name)
-{
-    int curr_edge = 0;
-    struct bu_list *vhead;
-    point_t a, b;
-    struct bn_vlblock *vbp;
-    struct bu_list local_vlist;
-
-    BU_LIST_INIT(&local_vlist);
-    vbp = bn_vlblock_init(&local_vlist, 32);
-
-    /* Clear any previous visual */
-    if (db_lookup(gedp->ged_wdbp->dbip, draw_name, LOOKUP_QUIET) != 
RT_DIR_NULL)
-       dl_erasePathFromDisplay(gedp->ged_gdp->gd_headDisplay, 
gedp->ged_wdbp->dbip, gedp->ged_free_vlist_callback, draw_name, 1, 
gedp->freesolid);
-
-    for (curr_edge = 0; curr_edge < num_edges; curr_edge++) {
-       int p1 = edges[curr_edge*2];
-       int p2 = edges[curr_edge*2+1];
-       VSET(a, bot->vertices[p1*3], bot->vertices[p1*3+1], 
bot->vertices[p1*3+2]);
-       VSET(b, bot->vertices[p2*3], bot->vertices[p2*3+1], 
bot->vertices[p2*3+2]);
-       vhead = bn_vlblock_find(vbp, draw_color[0], draw_color[1], 
draw_color[2]);
-       BN_ADD_VLIST(vbp->free_vlist_hd, vhead, a, BN_VLIST_LINE_MOVE);
-       BN_ADD_VLIST(vbp->free_vlist_hd, vhead, b, BN_VLIST_LINE_DRAW);
-    }
-
-    _ged_cvt_vlblock_to_solids(gedp, vbp, draw_name, 0);
-    bn_vlist_cleanup(&local_vlist);
-    bn_vlblock_free(vbp);
-}
-
-HIDDEN int
-bot_check(struct ged *gedp, int argc, const char *argv[], struct bu_opt_desc 
*d, struct rt_db_internal *ip, int visualize_results)
-{
-    const char *check = argv[1];
-    const char * const *sub, *subcommands[] = {"solid", "degen_faces", 
"open_edges", "extra_edges", "flipped_edges", NULL};
-    struct rt_bot_internal *bot = (struct rt_bot_internal *)ip->idb_ptr;
-    struct bg_trimesh_halfedge *edge_list;
-    int (*edge_test)(int, struct bg_trimesh_halfedge *, bg_edge_error_funct_t, 
void *);
-    int num_vertices, num_faces, num_edges;
-    int found;
-    int red[] = {255, 0, 0};
-    int blue[] = {0, 0, 255};
-    int yellow[] = {255, 255, 0};
-    int orange[] = {255, 128, 0};
-    int purple[] = {255, 0, 255};
-
-    /* must be wanting help */
-    if (argc < 2) {
-       _bot_show_help(gedp, d);
-       rt_db_free_internal(ip);
-       return GED_ERROR;
-    }
-
-    num_vertices = (int)bot->num_vertices;
-    num_faces = (int)bot->num_faces;
-    num_edges = num_faces * 3;
-
-    if (argc < 3 || BU_STR_EQUAL(check, "solid")) {
-       struct bg_trimesh_solid_errors errors = 
BG_TRIMESH_SOLID_ERRORS_INIT_NULL;
-       int not_solid;
-
-       if (bot->mode == RT_BOT_PLATE || bot->mode == RT_BOT_PLATE_NOCOS) {
-           bu_vls_printf(gedp->ged_result_str, "1");
-           rt_db_free_internal(ip);
-           return GED_OK;
-       }
-
-       not_solid = bg_trimesh_solid2(num_vertices, num_faces, bot->vertices, 
bot->faces, visualize_results ? &errors : NULL);
-       bu_vls_printf(gedp->ged_result_str, not_solid ? "0" : "1");
-
-       if (not_solid && visualize_results) {
-           struct bg_trimesh_edges *degen_edges = NULL, *all_edges, 
*other_edges;
-           struct bg_trimesh_edges error_lists[4];
-           int num_lists = 0;
-
-           error_lists[num_lists++] = errors.unmatched;
-           error_lists[num_lists++] = errors.misoriented;
-           error_lists[num_lists++] = errors.excess;
-           if (errors.degenerate.count > 0) {
-               degen_edges = face_edges(errors.degenerate, bot);
-               error_lists[num_lists++] = *degen_edges;
-           }
-
-           all_edges = edges_from_bot(bot);
-           other_edges = edges_not_in_lists(*all_edges, error_lists, 
num_lists);
-           bg_free_trimesh_edges(all_edges);
-           BU_FREE(all_edges, struct bg_trimesh_edges);
-
-           draw_edges(gedp, bot, other_edges->count, other_edges->edges, red, 
"other faces");
-           draw_edges(gedp, bot, errors.unmatched.count, 
errors.unmatched.edges, yellow, "unmatched edges");
-           draw_edges(gedp, bot, errors.misoriented.count, 
errors.misoriented.edges, orange, "misoriented edges");
-           draw_edges(gedp, bot, errors.excess.count, errors.excess.edges, 
purple, "excess edges");
-
-           if (errors.degenerate.count > 0) {
-               draw_edges(gedp, bot, degen_edges->count, degen_edges->edges, 
blue, "degenerate faces");
-
-               bg_free_trimesh_edges(degen_edges);
-               BU_FREE(degen_edges, struct bg_trimesh_edges);
-           }
-           bg_free_trimesh_edges(other_edges);
-           BU_FREE(other_edges, struct bg_trimesh_edges);
-           bg_free_trimesh_solid_errors(&errors);
-       }
-       rt_db_free_internal(ip);
-       return GED_OK;
-    }
-
-    /* check for one of the individual tests */
-    found = 0;
-    sub = subcommands;
-    for (; *sub != NULL; ++sub) {
-       if (BU_STR_EQUAL(check, *sub)) {
-           found = 1;
-           break;
-       }
-    }
-    if (!found) {
-       bu_vls_printf(gedp->ged_result_str, "check: %s is not a recognized 
check subcommand!\n", check);
-       rt_db_free_internal(ip);
-       return GED_ERROR;
-    }
-
-    /* face test */
-    if (BU_STR_EQUAL(check, "degen_faces")) {
-       struct bg_trimesh_faces degenerate = BG_TRIMESH_FACES_INIT_NULL;
-       struct bg_trimesh_edges *degen_edges, *all_edges, *other_edges;
-       int degenerate_faces = 0;
-
-       if (visualize_results) {
-           /* first pass - count errors */
-           degenerate_faces = bg_trimesh_degenerate_faces(num_faces, 
bot->faces, bg_trimesh_face_continue, NULL);
-
-           if (degenerate_faces) {
-               /* second pass - generate error faces array and draw it */
-               degenerate.count = 0;
-               degenerate.faces = (int *)bu_calloc(degenerate_faces, 
sizeof(int), "degenerate faces");
-               bg_trimesh_degenerate_faces(num_faces, bot->faces, 
bg_trimesh_face_gather, &degenerate);
-
-               degen_edges = face_edges(degenerate, bot);
-               bg_free_trimesh_faces(&degenerate);
-
-               all_edges = edges_from_bot(bot);
-               other_edges = edges_not_in_lists(*all_edges, degen_edges, 1);
-               bg_free_trimesh_edges(all_edges);
-               BU_FREE(all_edges, struct bg_trimesh_edges);
-
-               draw_edges(gedp, bot, degen_edges->count, degen_edges->edges, 
yellow, "degenerate faces");
-               draw_edges(gedp, bot, other_edges->count, other_edges->edges, 
red, "othererate faces");
-
-               bg_free_trimesh_edges(degen_edges);
-               BU_FREE(degen_edges, struct bg_trimesh_edges);
-               bg_free_trimesh_edges(other_edges);
-               BU_FREE(other_edges, struct bg_trimesh_edges);
-           }
-       } else {
-           /* fast path - exit on first error */
-           degenerate_faces = bg_trimesh_degenerate_faces(num_faces, 
bot->faces, bg_trimesh_face_exit, NULL);
-       }
-
-       bu_vls_printf(gedp->ged_result_str, degenerate_faces ? "1" : "0");
-
-       rt_db_free_internal(ip);
-       return GED_OK;
-    }
-
-    /* must be doing one of the edge tests */
-
-    /* generate half-edge list */
-    if (!(edge_list = bg_trimesh_generate_edge_list(num_faces, bot->faces))) {
-       rt_db_free_internal(ip);
-       bu_vls_printf(gedp->ged_result_str, "ERROR: failed to generate an edge 
list\n");
-       return GED_ERROR;
-    }
-
-    /* select edge test */
-    if (BU_STR_EQUAL(check, "open_edges")) {
-       edge_test = bg_trimesh_unmatched_edges;
-    } else if (BU_STR_EQUAL(check, "flipped_edges")) {
-       edge_test = bg_trimesh_misoriented_edges;
-    } else if (BU_STR_EQUAL(check, "extra_edges")) {
-       edge_test = bg_trimesh_excess_edges;
-    } else {
-       bu_vls_printf(gedp->ged_result_str, "ERROR: unrecognized edge test 
[%s]\n", check);
-       return GED_ERROR;
-    }
-
-    if (visualize_results) {
-       /* first pass - count errors */
-       struct bg_trimesh_edges error_edges = BG_TRIMESH_EDGES_INIT_NULL;
-       struct bg_trimesh_edges *all_edges, *other_edges;
-
-       found = edge_test(num_edges, edge_list, bg_trimesh_edge_continue, NULL);
-
-       if (found) {
-           /* second pass - generate error edge array and draw it */
-           error_edges.count = 0;
-           error_edges.edges = (int *)bu_calloc(found * 2, sizeof(int), "error 
edges");
-           found = edge_test(num_edges, edge_list, bg_trimesh_edge_gather, 
&error_edges);
-
-           all_edges = edges_from_half_edges(edge_list, num_edges);
-           other_edges = edges_not_in_lists(*all_edges, &error_edges, 1);
-           bg_free_trimesh_edges(all_edges);
-           BU_FREE(all_edges, struct bg_trimesh_edges);
-
-           draw_edges(gedp, bot, error_edges.count, error_edges.edges, yellow, 
"error edges");
-           draw_edges(gedp, bot, other_edges->count, other_edges->edges, red, 
"other edges");
-
-           bg_free_trimesh_edges(&error_edges);
-           bg_free_trimesh_edges(other_edges);
-           BU_FREE(other_edges, struct bg_trimesh_edges);
-       }
-    } else {
-       /* fast path - exit on first error */
-       found = edge_test(num_edges, edge_list, bg_trimesh_edge_exit, NULL);
-    }
-
-    bu_free(edge_list, "edge list");
-
-    bu_vls_printf(gedp->ged_result_str, found ? "1" : "0");
-    rt_db_free_internal(ip);
-    return GED_OK;
-}
-
-int
-ged_bot(struct ged *gedp, int argc, const char *argv[])
-{
-    struct directory *bot_dp;
-    struct rt_db_internal intern;
-    struct rt_bot_internal *bot;
-    const char *cmd = argv[0];
-    const char *sub = NULL;
-    const char *arg = NULL;
-    const char *primitive = NULL;
-    const char *primitive_2 = NULL;
-    size_t len;
-    fastf_t tmp;
-    fastf_t propVal;
-    int i;
-    int print_help = 0;
-    int visualize_results = 0;
-    int opt_ret = 0;
-    int opt_argc;
-    struct bu_opt_desc d[3];
-    const char * const bot_subcommands[] = {"check", "chull", "get", "isect", 
"remesh", NULL};
-    BU_OPT(d[0], "h", "help",      "", NULL, &print_help,        "Print help 
and exit");
-    BU_OPT(d[1], "V", "visualize", "", NULL, &visualize_results, "Use 
subcommand's 3D visualization.");
-    BU_OPT_NULL(d[2]);
-
-    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);
-
-    /* must be wanting help */
-    if (argc < 3) {
-       _bot_show_help(gedp, d);
-       return GED_ERROR;
-    }
-
-    /* See if we have any options to deal with.  Once we hit a subcommand, 
we're done */
-    opt_argc = argc;
-    for (i = 1; i < argc; ++i) {
-       const char * const *subcmd = bot_subcommands;
-
-       for (; *subcmd != NULL; ++subcmd) {
-           if (BU_STR_EQUAL(argv[i], *subcmd)) {
-               opt_argc = i;
-               i = argc;
-               break;
-           }
-       }
-    }
-
-    if (opt_argc >= argc) {
-       /* no subcommand given */
-       _bot_show_help(gedp, d);
-       return GED_ERROR;
-    }
-
-    if (opt_argc > 1) {
-       /* parse standard options */
-       opt_ret = bu_opt_parse(NULL, opt_argc, argv, d);
-       if (opt_ret < 0) _bot_show_help(gedp, d);
-    }
-
-    /* shift past standard options to subcommand args */
-    argc -= opt_argc;
-    argv = &argv[opt_argc];
-
-    if (argc < 2) {
-       _bot_show_help(gedp, d);
-       return GED_ERROR;
-    }
-
-    /* determine subcommand */
-    sub = argv[0];
-    len = strlen(sub);
-    if (bu_strncmp(sub, "get", len) == 0) {
-       primitive = argv[argc - 1];
-    } else if (bu_strncmp(sub, "chull", len) == 0) {
-       primitive = argv[1];
-       primitive_2 = argv[2];
-    } else if (bu_strncmp(sub, "isect", len) == 0) {
-       primitive = argv[1];
-       primitive_2 = argv[2];
-    } else if (bu_strncmp(sub, "check", len) == 0) {
-       primitive = argv[argc - 1];
-    } else if (bu_strncmp(sub, "remesh", len) == 0) {
-       primitive = argv[1];
-       primitive_2 = argv[2];
-    } else {
-       bu_vls_printf(gedp->ged_result_str, "%s: %s is not a known 
subcommand!", cmd, sub);
-       return GED_ERROR;
-    }
-
-    /* get bot */
-    GED_DB_LOOKUP(gedp, bot_dp, primitive, LOOKUP_NOISY, GED_ERROR & 
GED_QUIET);
-    GED_DB_GET_INTERNAL(gedp, &intern, bot_dp, bn_mat_identity, 
&rt_uniresource, GED_ERROR);
-
-    if (intern.idb_major_type != DB5_MAJORTYPE_BRLCAD || intern.idb_minor_type 
!= DB5_MINORTYPE_BRLCAD_BOT) {
-       bu_vls_printf(gedp->ged_result_str, "%s: %s is not a BOT solid!", cmd, 
primitive);
-       rt_db_free_internal(&intern);
-       return GED_ERROR;
-    }
-
-    bot = (struct rt_bot_internal *)intern.idb_ptr;
-    RT_BOT_CK_MAGIC(bot);
-
-    if (bu_strncmp(sub, "get", len) == 0) {
-       arg = argv[1];
-       propVal = rt_bot_propget(bot, arg);
-
-       /* print result string */
-       if (!EQUAL(propVal, -1.0)) {
-
-           tmp = (int) propVal;
-
-           /* int result */
-           if (EQUAL(propVal, tmp)) {
-               bu_vls_printf(gedp->ged_result_str, "%d", (int) propVal);
-           }
-
-           /* float result */
-           else {
-               bu_vls_printf(gedp->ged_result_str, "%f", propVal);
-           }
-       } else {
-           bu_vls_printf(gedp->ged_result_str, "%s: %s is not a valid 
argument!", sub, arg);
-           rt_db_free_internal(&intern);
-           return GED_ERROR;
-       }
-
-    } else if (bu_strncmp(sub, "chull", len) == 0) {
-
-       int retval = 0;
-       int fc = 0;
-       int vc = 0;
-       point_t *vert_array;
-       int *faces;
-       unsigned char err = 0;
-
-       /* must be wanting help */
-       if (argc < 3) {
-           _bot_show_help(gedp, d);
-           rt_db_free_internal(&intern);
-           return GED_ERROR;
-       }
-
-       retval = bg_3d_chull(&faces, &fc, &vert_array, &vc, (const point_t 
*)bot->vertices, (int)bot->num_vertices);
-
-       if (retval != 3) {
-           rt_db_free_internal(&intern);
-           return GED_ERROR;
-       }
-
-       retval = mk_bot(gedp->ged_wdbp, primitive_2, RT_BOT_SOLID, RT_BOT_CCW, 
err, vc, fc, (fastf_t *)vert_array, faces, NULL, NULL);
-
-       bu_free(faces, "free faces");
-       bu_free(vert_array, "free verts");
-
-       if (retval) {
-           rt_db_free_internal(&intern);
-           return GED_ERROR;
-       }
-
-    } else if (bu_strncmp(sub, "isect", len) == 0) {
-
-       struct directory *bot_dp_2;
-       struct rt_db_internal intern_2;
-       struct rt_bot_internal *bot_2;
-
-       /* must be wanting help */
-       if (argc < 3) {
-           _bot_show_help(gedp, d);
-           rt_db_free_internal(&intern);
-           return GED_ERROR;
-       }
-
-       GED_DB_LOOKUP(gedp, bot_dp_2, primitive_2, LOOKUP_NOISY, GED_ERROR & 
GED_QUIET);
-       GED_DB_GET_INTERNAL(gedp, &intern_2, bot_dp_2, bn_mat_identity, 
&rt_uniresource, GED_ERROR);
-
-       if (intern_2.idb_major_type != DB5_MAJORTYPE_BRLCAD || 
intern_2.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) {
-           bu_vls_printf(gedp->ged_result_str, "%s: %s is not a BOT solid!", 
cmd, primitive_2);
-           rt_db_free_internal(&intern_2);
-           rt_db_free_internal(&intern);
-           return GED_ERROR;
-       }
-       bot_2 = (struct rt_bot_internal *)intern_2.idb_ptr;
-
-       {
-       int fc_1 = (int)bot->num_faces;
-       int fc_2 = (int)bot_2->num_faces;
-       int vc_1 = (int)bot->num_vertices;
-       int vc_2 = (int)bot_2->num_vertices;
-       point_t *verts_1 = (point_t *)bot->vertices;
-       point_t *verts_2 = (point_t *)bot_2->vertices;
-       int *faces_1 = bot->faces;
-       int *faces_2 = bot_2->faces;
-
-       (void)bg_trimesh_isect(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-              faces_1, fc_1, verts_1, vc_1, faces_2, fc_2, verts_2, vc_2);
-
-       rt_db_free_internal(&intern);
-       rt_db_free_internal(&intern_2);
-       return GED_OK;
-       }
-
-    } else if (bu_strncmp(sub, "check", len) == 0) {
-
-       return bot_check(gedp, argc, argv, d, &intern, visualize_results);
-
-    } else if (bu_strncmp(sub, "remesh", len) == 0) {
-
-       return ged_bot_remesh(gedp, argc, argv);
-
-    }
-
-    rt_db_free_internal(&intern);
-
-    return GED_OK;
-}
-
-
-/*
- * Local Variables:
- * tab-width: 8
- * mode: C
- * indent-tabs-mode: t
- * c-file-style: "stroustrup"
- * End:
- * ex: shiftwidth=4 tabstop=8
- */

Deleted: brlcad/trunk/src/libged/bot_remesh.cpp
===================================================================
--- brlcad/trunk/src/libged/bot_remesh.cpp      2020-05-01 17:33:34 UTC (rev 
75662)
+++ brlcad/trunk/src/libged/bot_remesh.cpp      2020-05-01 21:39:07 UTC (rev 
75663)
@@ -1,260 +0,0 @@
-/*                     B O T _ R E M E S H . C P P
- * BRL-CAD
- *
- * Copyright (c) 2019-2020 United States Government as represented by
- * the U.S. Army Research Laboratory.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this file; see the file named COPYING for more
- * information.
- */
-/** @file libged/bot_remesh.cpp
- *
- * The bot "remesh" sub-command.
- *
- */
-
-#include "common.h"
-
-#ifdef OPENVDB_ABI_VERSION_NUMBER
-#  include <openvdb/openvdb.h>
-#  include <openvdb/tools/VolumeToMesh.h>
-#  include <openvdb/tools/MeshToVolume.h>
-#endif /* OPENVDB_ABI_VERSION_NUMBER */
-
-#include "vmath.h"
-#include "bu/str.h"
-#include "rt/db5.h"
-#include "rt/db_internal.h"
-#include "rt/db_io.h"
-#include "rt/geom.h"
-#include "rt/wdb.h"
-#include "ged/commands.h"
-#include "ged/database.h"
-#include "ged/objects.h"
-
-
-#ifdef OPENVDB_ABI_VERSION_NUMBER
-
-struct botDataAdapter {
-    struct rt_bot_internal *bot;
-
-    size_t polygonCount() const {
-       return bot->num_faces;
-    };
-    size_t pointCount() const {
-       return bot->num_vertices;
-    };
-    size_t vertexCount(size_t) const {
-       return 3;
-    };
-    void getIndexSpacePoint(size_t n, size_t v, openvdb::Vec3d& pos) const {
-       int idx = bot->faces[(n*3)+v];
-       pos[X] = bot->vertices[(idx*3)+X];
-       pos[Y] = bot->vertices[(idx*3)+Y];
-       pos[Z] = bot->vertices[(idx*3)+Z];
-       return;
-    };
-
-    /* constructor */
-    botDataAdapter(struct rt_bot_internal *bip) : bot(bip) {}
-};
-
-
-static bool
-bot_remesh(struct ged *UNUSED(gedp), struct rt_bot_internal *bot, double 
voxelSize)
-{
-    const float exteriorBandWidth = 10.0;
-    const float interiorBandWidth = std::numeric_limits<float>::max();
-
-    struct botDataAdapter bda(bot);
-
-    openvdb::initialize();
-
-    bu_log("...voxelizing");
-
-    openvdb::math::Transform::Ptr xform = 
openvdb::math::Transform::createLinearTransform(voxelSize);
-    openvdb::FloatGrid::Ptr bot2vol = 
openvdb::tools::meshToVolume<openvdb::FloatGrid, botDataAdapter>(bda, *xform, 
exteriorBandWidth, interiorBandWidth);
-
-#if 0
-    openvdb::io::File file("mesh.vdb");
-    openvdb::GridPtrVec grids;
-    grids.push_back(bot2vol);
-    file.write(grids);
-    file.close();
-    return false;
-#endif
-
-    bu_log("...devoxelizing");
-
-    std::vector<openvdb::Vec3s> points;
-    std::vector<openvdb::Vec3I> triangles;
-    std::vector<openvdb::Vec4I> quadrilaterals;
-    openvdb::tools::volumeToMesh<openvdb::FloatGrid>(*bot2vol, points, 
triangles, quadrilaterals);
-
-    bu_log("...storing");
-
-    if (bot->vertices) {
-       bu_free(bot->vertices, "vertices");
-       bot->num_vertices = 0;
-    }
-    if (bot->faces) {
-       bu_free(bot->faces, "faces");
-       bot->num_faces = 0;
-    }
-    if (bot->normals) {
-       bu_free(bot->normals, "normals");
-    }
-    if (bot->face_normals) {
-       bu_free(bot->face_normals, "face normals");
-    }
-
-    bot->num_vertices = points.size();
-    bot->vertices = (fastf_t *)bu_malloc(bot->num_vertices * 
ELEMENTS_PER_POINT * sizeof(fastf_t), "vertices");
-    for (size_t i = 0; i < points.size(); i++) {
-       bot->vertices[(i*3)+X] = points[i].x();
-       bot->vertices[(i*3)+Y] = points[i].y();
-       bot->vertices[(i*3)+Z] = points[i].z();
-    }
-    bot->num_faces = triangles.size() + (quadrilaterals.size() * 2);
-    bot->faces = (int *)bu_malloc(bot->num_faces * 3 * sizeof(int), 
"triangles");
-    for (size_t i = 0; i < triangles.size(); i++) {
-       bot->faces[(i*3)+X] = triangles[i].x();
-       bot->faces[(i*3)+Y] = triangles[i].y();
-       bot->faces[(i*3)+Z] = triangles[i].z();
-    }
-    size_t ntri = triangles.size();
-    for (size_t i = 0; i < quadrilaterals.size(); i++) {
-       bot->faces[((ntri+i)*3)+X] = quadrilaterals[i][0];
-       bot->faces[((ntri+i)*3)+Y] = quadrilaterals[i][1];
-       bot->faces[((ntri+i)*3)+Z] = quadrilaterals[i][2];
-
-       bot->faces[((ntri+i+1)*3)+X] = quadrilaterals[i][0];
-       bot->faces[((ntri+i+1)*3)+Y] = quadrilaterals[i][2];
-       bot->faces[((ntri+i+1)*3)+Z] = quadrilaterals[i][3];
-    }
-
-    bu_log("...done!\n");
-
-    return (points.size() > 0);
-}
-
-#else /* OPENVDB_ABI_VERSION_NUMBER */
-
-static bool
-bot_remesh(struct ged *gedp, struct rt_bot_internal *UNUSED(bot), double 
UNUSED(voxelSize))
-{
-    bu_vls_printf(gedp->ged_result_str,
-                 "WARNING: BoT remeshing is unavailable.\n"
-                 "BRL-CAD needs to be compiled with OpenVDB support.\n"
-                 "(cmake -DBRLCAD_ENABLE_OPENVDB=ON)\n");
-    return false;
-}
-
-#endif /* OPENVDB_ABI_VERSION_NUMBER */
-
-
-int
-ged_bot_remesh(struct ged *gedp, int argc, const char *argv[])
-{
-    static const char *usage = "input.bot [output.bot]";
-
-    char *input_bot_name;
-    char *output_bot_name;
-    struct directory *dp_input;
-    struct directory *dp_output;
-    struct rt_bot_internal *input_bot;
-    struct rt_db_internal intern;
-
-    GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
-    GED_CHECK_READ_ONLY(gedp, GED_ERROR);
-    GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
-
-    dp_input = dp_output = RT_DIR_NULL;
-
-    /* initialize result */
-    bu_vls_trunc(gedp->ged_result_str, 0);
-
-    /* must be wanting help */
-    if (argc == 1) {
-       bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
-       return GED_HELP;
-    }
-
-    /* check that we are using a version 5 database */
-    if (db_version(gedp->ged_wdbp->dbip) < 5) {
-       bu_vls_printf(gedp->ged_result_str,
-                     "ERROR: Unable to remesh the current (v%d) database.\n"
-                     "Use \"dbupgrade\" to upgrade this database to the 
current version.\n",
-                     db_version(gedp->ged_wdbp->dbip));
-       return GED_ERROR;
-    }
-
-    if (argc > 3) {
-       bu_vls_printf(gedp->ged_result_str, "ERROR: unexpected arguments 
encountered\n");
-       bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
-       return GED_ERROR;
-    }
-
-    input_bot_name = output_bot_name = (char *)argv[1];
-    if (argc > 2)
-       output_bot_name = (char *)argv[2];
-
-    if (!BU_STR_EQUAL(input_bot_name, output_bot_name)) {
-       GED_CHECK_EXISTS(gedp, output_bot_name, LOOKUP_QUIET, GED_ERROR);
-    }
-
-    GED_DB_LOOKUP(gedp, dp_input, input_bot_name, LOOKUP_QUIET, GED_ERROR);
-    GED_DB_GET_INTERNAL(gedp, &intern, dp_input, NULL, 
gedp->ged_wdbp->wdb_resp, GED_ERROR);
-
-    if (intern.idb_major_type != DB5_MAJORTYPE_BRLCAD || intern.idb_minor_type 
!= DB5_MINORTYPE_BRLCAD_BOT) {
-       bu_vls_printf(gedp->ged_result_str, "%s is not a BOT primitive\n", 
input_bot_name);
-       rt_db_free_internal(&intern);
-       return GED_ERROR;
-    }
-
-    input_bot = (struct rt_bot_internal *)intern.idb_ptr;
-    RT_BOT_CK_MAGIC(input_bot);
-
-    bu_log("INPUT BoT has %zu vertices and %zu faces\n", 
input_bot->num_vertices, input_bot->num_faces);
-
-    /* TODO: stash a backup if overwriting the original */
-
-    bool ok = bot_remesh(gedp, input_bot, 50);
-    if (!ok) {
-       return GED_ERROR;
-    }
-
-    bu_log("OUTPUT BoT has %zu vertices and %zu faces\n", 
input_bot->num_vertices, input_bot->num_faces);
-
-    if (BU_STR_EQUAL(input_bot_name, output_bot_name)) {
-       dp_output = dp_input;
-    } else {
-       GED_DB_DIRADD(gedp, dp_output, output_bot_name, RT_DIR_PHONY_ADDR, 0, 
RT_DIR_SOLID, (void *)&intern.idb_type, GED_ERROR);
-    }
-
-    GED_DB_PUT_INTERNAL(gedp, dp_output, &intern, gedp->ged_wdbp->wdb_resp, 
GED_ERROR);
-    rt_db_free_internal(&intern);
-
-    return GED_OK;
-}
-
-
-/*
- * Local Variables:
- * tab-width: 8
- * mode: C
- * indent-tabs-mode: t
- * c-file-style: "stroustrup"
- * End:
- * ex: shiftwidth=4 tabstop=8
- */

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