Revision: 75656
          http://sourceforge.net/p/brlcad/code/75656
Author:   starseeker
Date:     2020-05-01 13:33:08 +0000 (Fri, 01 May 2020)
Log Message:
-----------
Add a C++ version of the check.tcl/check.sh logic.  Idea is to allow generating 
overlap files independent of MGED and without requiring unix shells/commands.

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

Added Paths:
-----------
    brlcad/trunk/src/gtools/gchecker.cpp

Modified: brlcad/trunk/src/gtools/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/gtools/CMakeLists.txt      2020-05-01 03:55:28 UTC (rev 
75655)
+++ brlcad/trunk/src/gtools/CMakeLists.txt      2020-05-01 13:33:08 UTC (rev 
75656)
@@ -16,6 +16,7 @@
 BRLCAD_ADDEXEC(gex "gex.cpp" "libbu;librt")
 BRLCAD_ADDEXEC(glint glint.cpp "librt;${M_LIBRARY}")
 BRLCAD_ADDEXEC(gqa gqa.c "libged;librt")
+BRLCAD_ADDEXEC(gchecker gchecker.cpp "libged;librt;libbu")
 
 set(GSH_SRCS
   gsh.cpp

Added: brlcad/trunk/src/gtools/gchecker.cpp
===================================================================
--- brlcad/trunk/src/gtools/gchecker.cpp                                (rev 0)
+++ brlcad/trunk/src/gtools/gchecker.cpp        2020-05-01 13:33:08 UTC (rev 
75656)
@@ -0,0 +1,387 @@
+/*                    G C H E C K E R . 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 gchecker.cpp
+ *
+ * C++ version of the check.tcl logic generating overlap files used
+ * by the MGED Overlap Tool
+ *
+ */
+
+#include "common.h"
+
+#ifdef HAVE_SYS_STAT_H
+#  include <sys/stat.h> /* for mkdir */
+#endif
+
+#include <fstream>
+#include <iostream>
+#include <iomanip>
+#include <regex>
+#include <set>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "bu/app.h"
+#include "bu/file.h"
+#include "bu/opt.h"
+#include "bu/path.h"
+#include "ged.h"
+
+static void
+_cmd_help(const char *usage, struct bu_opt_desc *d)
+{
+    struct bu_vls str = BU_VLS_INIT_ZERO;
+    char *option_help;
+
+    bu_vls_sprintf(&str, "%s", usage);
+
+    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_log("%s", bu_vls_cstr(&str));
+    bu_vls_free(&str);
+}
+
+
+int
+main(int argc, const char **argv)
+{
+    int print_help = 0;
+    int dry_run = 0;
+    int verbose = 0;
+    const char *usage = "Usage: gchecker [options] file.g  [objects ...]\n\n";
+    struct bu_opt_desc d[4];
+    BU_OPT(d[0], "h", "help",    "",  NULL, &print_help, "Print help and 
exit");
+    BU_OPT(d[1], "d", "dry-run", "",  NULL, &dry_run,    "Step through the 
checker stages, but don't raytrace");
+    BU_OPT(d[2], "v", "verbose", "",  NULL, &verbose,    "Print verbose 
information about result processing");
+    BU_OPT_NULL(d[3]);
+
+    std::set<std::pair<std::string, std::string>> unique_pairs;
+    std::multimap<std::pair<std::string, std::string>, double> pair_sizes;
+    std::map<std::pair<std::string, std::string>, double> pair_avg_sizes;
+
+
+    bu_setprogname(argv[0]);
+
+    argc-=(argc>0); argv+=(argc>0);
+
+       /* must be wanting help */
+    if (argc < 1) {
+        _cmd_help(usage, d);
+        return 0;
+    }
+
+    /* parse standard options */
+    int opt_ret = bu_opt_parse(NULL, argc, argv, d);
+
+    if (print_help) {
+        _cmd_help(usage, d);
+        return 0;
+    }
+
+    /* adjust argc to match the leftovers of the options parsing */
+    argc = opt_ret;
+
+    if (argc < 1) {
+       _cmd_help(usage, d);
+       return 1;
+    }
+
+
+    char gqa_exe[MAXPATHLEN] = {0};
+    char mged_exe[MAXPATHLEN] = {0};
+    char rtcheck_exe[MAXPATHLEN] = {0};
+    bu_dir(gqa_exe, MAXPATHLEN, BU_DIR_BIN, "gqa", BU_DIR_EXT, NULL);
+    bu_dir(mged_exe, MAXPATHLEN, BU_DIR_BIN, "mged", BU_DIR_EXT, NULL);
+    bu_dir(rtcheck_exe, MAXPATHLEN, BU_DIR_BIN, "rtcheck", BU_DIR_EXT, NULL);
+
+    if (!bu_file_exists(gqa_exe, NULL)) {
+       bu_exit(1, "could not locate gqa executable");
+    }
+    if (!bu_file_exists(mged_exe, NULL)) {
+       bu_exit(1, "could not locate mged executable");
+    }
+    if (!bu_file_exists(rtcheck_exe, NULL)) {
+       bu_exit(1, "could not locate rtcheck executable");
+    }
+
+    // Have programs - see if we have the .g file
+    struct bu_vls gfile = BU_VLS_INIT_ZERO;
+    bu_vls_sprintf(&gfile, "%s", argv[0]);
+    if (!bu_file_exists(bu_vls_cstr(&gfile), NULL)) {
+       char fpgfile[MAXPATHLEN] = {0};
+       bu_dir(fpgfile, MAXPATHLEN, BU_DIR_CURR, bu_vls_cstr(&gfile), NULL);
+       bu_vls_sprintf(&gfile, "%s", fpgfile);
+       if (!bu_file_exists(bu_vls_cstr(&gfile), NULL)) {
+           bu_vls_free(&gfile);
+           bu_exit(1, "file %s does not exist", argv[0]);
+       }
+    }
+
+    struct bu_vls gbasename = BU_VLS_INIT_ZERO;
+    if (!bu_path_component(&gbasename, bu_vls_cstr(&gfile), BU_PATH_BASENAME)) 
{
+       bu_vls_free(&gfile);
+       bu_exit(1, "Could not identify basename in geometry file path \"%s\"", 
argv[0]);
+    }
+    struct bu_vls wdir = BU_VLS_INIT_ZERO;
+    bu_vls_printf(&wdir, "%s.ck", bu_vls_cstr(&gbasename));
+    if (bu_file_exists(bu_vls_cstr(&wdir), NULL)) {
+       bu_vls_free(&gfile);
+       bu_vls_free(&gbasename);
+       bu_exit(1, "Working directory\"%s\" already exists - remove to 
continue", bu_vls_cstr(&wdir));
+    }
+
+
+    if (dry_run) {
+       bu_log("(Note: dry run - skipping rtcheck)\n");
+    }
+
+    // Make the working directory
+#ifdef HAVE_WINDOWS_H
+    CreateDirectory(bu_vls_cstr(&wdir), NULL);
+#else
+    /* mode: 775 */
+    mkdir(bu_vls_cstr(&wdir), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+#endif
+
+    // Put a copy of the .g file in the working directory
+    std::ifstream sgfile(bu_vls_cstr(&gfile), std::ios::binary);
+    std::ofstream dgfile;
+    dgfile.open(bu_dir(NULL, 0, bu_vls_cstr(&wdir), bu_vls_cstr(&gbasename), 
NULL), std::ios::binary);
+    dgfile << sgfile.rdbuf();
+    dgfile.close();
+    sgfile.close();
+
+    // Change working directory
+    chdir(bu_vls_cstr(&wdir));
+
+    if (verbose) {
+       bu_log("Working on a copy in %s\n", bu_vls_cstr(&wdir));
+    }
+
+    // All set - open up the .g file and go to work.
+    struct ged *gedp = ged_open("db", bu_vls_cstr(&gbasename), 1);
+    if (gedp == GED_NULL) {
+       bu_exit(1, "Failed to open \"%s\" ", bu_vls_cstr(&gbasename));
+    }
+
+    // Make sure our reference counts are up to date, so we can tell
+    // which objects are top level
+    db_update_nref(gedp->ged_wdbp->dbip, &rt_uniresource);
+
+    std::vector<struct directory *> objs;
+    if (argc > 1) {
+       for (int i = 1; i < argc; i++) {
+           struct directory *dp = db_lookup(gedp->ged_wdbp->dbip, argv[i], 
LOOKUP_QUIET);
+           if (dp == RT_DIR_NULL) {
+               bu_exit(1, "Failed to open object \"%s\" in \"%s\" ", argv[i], 
bu_vls_cstr(&gbasename));
+           }
+           objs.push_back(dp);
+       }
+    } else {
+       // Get all top level objects
+       struct directory **all_paths;
+       int obj_cnt = db_ls(gedp->ged_wdbp->dbip, DB_LS_TOPS, NULL, &all_paths);
+       for (int i = 0; i < obj_cnt; i++) {
+           objs.push_back(all_paths[i]);
+       }
+       bu_free(all_paths, "free db_tops output");
+    }
+
+    if (objs.size() == 1) {
+       bu_log("Processing tops object: %s\n", objs[0]->d_namep);
+    } else {
+       bu_log("Processing tops objects:\n");
+       for (size_t i = 0; i < objs.size(); i++) {
+           bu_log("   %s\n", objs[i]->d_namep);
+       }
+    }
+
+    int total_views = 0;
+    for (size_t i = 0; i < objs.size(); i++) {
+       for (int az = 0; az < 180; az+=45) {
+           for (int el = 0; el < 180; el+=45) {
+               total_views++;
+           }
+       }
+    }
+
+    if (total_views != (int)(16 * objs.size())) {
+       bu_exit(1, "view incrementing error\n");
+    }
+
+    // Run rtcheck equiv.
+    if (!dry_run) {
+       std::regex oregex("<(.*),.(.*)>: ([0-9]*).* (.*).mm");
+       for (size_t i = 0; i < objs.size(); i++) {
+           for (int az = 0; az < 180; az+=45) {
+               for (int el = 0; el < 180; el+=45) {
+                   struct bu_vls str = BU_VLS_INIT_ZERO;
+                   const char **av = (const char **)bu_calloc(8, sizeof(char 
*), "cmd array");
+                   av[0] = bu_strdup("check");
+                   av[1] = bu_strdup("overlaps");
+                   av[2] = bu_strdup("-G1024");
+                   bu_vls_sprintf(&str, "-a%d", az);
+                   av[3] = bu_strdup(bu_vls_cstr(&str));
+                   bu_vls_sprintf(&str, "-e%d", el);
+                   av[4] = bu_strdup(bu_vls_cstr(&str));
+                   av[5] = bu_strdup("-q");
+                   av[6] = bu_strdup(objs[i]->d_namep);
+                   bu_vls_trunc(gedp->ged_result_str, 0);
+                   if (ged_check(gedp, 7, av) != GED_OK) {
+                       bu_exit(1, "error running ged_check\n");
+                   }
+                   for (int j = 0; j < 7; j++) bu_free((void *)av[j], "str");
+                   bu_free(av, "av array");
+                   bu_vls_free(&str);
+
+                   // Split up results into something we can process with regex
+                   std::istringstream sres(bu_vls_cstr(gedp->ged_result_str));
+                   std::string line;
+                   while (std::getline(sres, line)) {
+                       std::smatch nvar;
+                       if (!std::regex_search(line, nvar, oregex) || 
nvar.size() != 5) {
+                           continue;
+                       }
+                       if (verbose) {
+                           bu_log("%zd: %s\n", nvar.size(), line.c_str());
+                           for (size_t m = 0; m < nvar.size(); m++) {
+                               bu_log("   %zd: %s\n", m, nvar.str(m).c_str());
+                           }
+                       }
+                       std::pair<std::string, std::string> key;
+                       // sort left and right strings lexicographically to 
produce unique pairing keys
+                       key = (nvar.str(1) < nvar.str(2)) ? 
std::make_pair(nvar.str(1), nvar.str(2)) :  std::make_pair(nvar.str(2), 
nvar.str(1));
+                       // size = count * depth
+                       double val = std::stod(nvar.str(3)) * 
std::stod(nvar.str(4));
+                       unique_pairs.insert(key);
+                       pair_sizes.insert(std::make_pair(key, val));
+                       if (verbose) {
+                           bu_log("Inserting: %s,%s -> %f\n", 
key.first.c_str(), key.second.c_str(), val);
+                       }
+                   }
+               }
+           }
+       }
+
+       // Run gqa equiv.
+       for (size_t i = 0; i < objs.size(); i++) {
+           for (int az = 0; az < 180; az+=45) {
+               for (int el = 0; el < 180; el+=45) {
+                   const char **av = (const char **)bu_calloc(6, sizeof(char 
*), "cmd array");
+                   av[0] = bu_strdup("check");
+                   av[1] = bu_strdup("overlaps");
+                   av[2] = bu_strdup("-g1mm,1mm");
+                   av[3] = bu_strdup("-q");
+                   av[4] = bu_strdup(objs[i]->d_namep);
+                   bu_vls_trunc(gedp->ged_result_str, 0);
+                   if (ged_check(gedp, 5, av) != GED_OK) {
+                       bu_exit(1, "error running ged_check\n");
+                   }
+                   for (int j = 0; j < 5; j++) bu_free((void *)av[j], "str");
+                   bu_free(av, "av array");
+
+                   // Split up results into something we can process with regex
+                   std::istringstream sres(bu_vls_cstr(gedp->ged_result_str));
+                   std::string line;
+                   while (std::getline(sres, line)) {
+                       std::smatch nvar;
+                       if (!std::regex_search(line, nvar, oregex) || 
nvar.size() != 5) {
+                           continue;
+                       }
+                       if (verbose) {
+                           bu_log("%zd: %s\n", nvar.size(), line.c_str());
+                           for (size_t m = 0; m < nvar.size(); m++) {
+                               bu_log("   %zd: %s\n", m, nvar.str(m).c_str());
+                           }
+                       }
+                       std::pair<std::string, std::string> key;
+                       // sort left and right strings lexicographically to 
produce unique pairing keys
+                       key = (nvar.str(1) < nvar.str(2)) ? 
std::make_pair(nvar.str(1), nvar.str(2)) :  std::make_pair(nvar.str(2), 
nvar.str(1));
+                       // size = count * depth
+                       double val = std::stod(nvar.str(3)) * 
std::stod(nvar.str(4));
+                       unique_pairs.insert(key);
+                       pair_sizes.insert(std::make_pair(key, val));
+                       if (verbose) {
+                           bu_log("Inserting: %s,%s -> %f\n", 
key.first.c_str(), key.second.c_str(), val);
+                       }
+                   }
+               }
+           }
+       }
+    }
+
+    if (verbose) {
+       bu_log("Found %zd unique pairings: \n", unique_pairs.size());
+    }
+    std::set<std::pair<std::string, std::string>>::iterator p_it;
+    for (p_it = unique_pairs.begin(); p_it != unique_pairs.end(); p_it++) {
+       if (verbose) {
+           bu_log("     %s + %s: \n", p_it->first.c_str(), 
p_it->second.c_str());
+       }
+       // For each pairing, get the average size
+       size_t scnt = pair_sizes.count(*p_it);
+       double ssum = 0.0;
+       if (verbose) {
+           bu_log("     Have %zd sizes: \n", scnt);
+       }
+       std::multimap<std::pair<std::string, std::string>, double>::iterator 
s_it;
+       for (s_it = pair_sizes.equal_range(*p_it).first; s_it != 
pair_sizes.equal_range(*p_it).second; s_it++) {
+           double s = (*s_it).second;
+           ssum += s;
+           if (verbose) {
+               bu_log("                   %f \n", s);
+           }
+       }
+       if (verbose) {
+           bu_log("     Avg: %f\n", ssum/(double)scnt);
+       }
+       pair_avg_sizes[*p_it] = ssum/(double)scnt;
+    }
+
+    std::string ofile = std::string("ck.") + 
std::string(bu_vls_cstr(&gbasename)) + std::string(".overlaps");
+    std::ofstream of(ofile);
+    std::map<std::pair<std::string, std::string>, double>::iterator a_it;
+    for (a_it = pair_avg_sizes.begin(); a_it != pair_avg_sizes.end(); a_it++) {
+       bu_log("%s + %s: %f\n", a_it->first.first.c_str(), 
a_it->first.second.c_str(), a_it->second);
+       of << a_it->first.first.c_str() << " " << a_it->first.second.c_str() << 
" " << std::fixed << std::setprecision(5) << a_it->second << "\n";
+    }
+    of.close();
+
+    // Remove the copy of the .g file
+    std::remove(bu_vls_cstr(&gbasename));
+
+    // Clean up
+    bu_vls_free(&gfile);
+    bu_vls_free(&gbasename);
+    bu_vls_free(&wdir);
+}
+
+// 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/gtools/gchecker.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
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