Revision: 78153
          http://sourceforge.net/p/brlcad/code/78153
Author:   starseeker
Date:     2021-01-30 15:23:40 +0000 (Sat, 30 Jan 2021)
Log Message:
-----------
Rough in a version of the "tree diff" capability under the gdiff command.

Modified Paths:
--------------
    brlcad/trunk/src/libged/gdiff/gdiff.c

Modified: brlcad/trunk/src/libged/gdiff/gdiff.c
===================================================================
--- brlcad/trunk/src/libged/gdiff/gdiff.c       2021-01-30 15:16:20 UTC (rev 
78152)
+++ brlcad/trunk/src/libged/gdiff/gdiff.c       2021-01-30 15:23:40 UTC (rev 
78153)
@@ -29,10 +29,164 @@
 
 #include "bu/cmd.h"
 #include "bu/opt.h"
+#include "rt/db_fullpath.h"
+#include "rt/db_diff.h"
 #include "analyze.h"
 
 #include "../ged_private.h"
 
+static void check_walk(
+       int *diff,
+               struct bu_vls *msgs,
+               struct db_i *dbip,
+       struct db_full_path *p1,
+       struct db_full_path *p2);
+static void
+check_walk_subtree(int *diff, struct bu_vls *msgs, struct db_i *dbip, struct 
db_full_path *p1, struct db_full_path *p2, union tree *tp1, union tree *tp2)
+{
+    int idn1, idn2;
+    struct directory *dp1, *dp2;
+
+    if (!diff)
+               return;
+
+    if ((!tp1 && tp2) || (tp1 && !tp2)) {
+       (*diff) = 1;
+       return;
+    }
+
+    if (!tp1 || !tp2)
+       return;
+
+    if (tp1->tr_op != tp2->tr_op) {
+       (*diff) = 1;
+       return;
+    }
+
+    switch (tp1->tr_op) {
+       case OP_DB_LEAF:
+           idn1 = (!tp1->tr_l.tl_mat || bn_mat_is_identity(tp1->tr_l.tl_mat));
+           idn2 = (!tp2->tr_l.tl_mat || bn_mat_is_identity(tp2->tr_l.tl_mat));
+           if (idn1 != idn2) {
+               (*diff) = 1;
+               return;
+           }
+           if (tp1->tr_l.tl_mat && tp2->tr_l.tl_mat) {
+               if (!bn_mat_is_equal(tp1->tr_l.tl_mat, tp2->tr_l.tl_mat, 
&dbip->dbi_wdbp->wdb_tol)) {
+                   (*diff) = 1;
+                   return;
+               }
+           }
+
+           dp1 = db_lookup(dbip, tp1->tr_l.tl_name, LOOKUP_NOISY);
+           dp2 = db_lookup(dbip, tp2->tr_l.tl_name, LOOKUP_NOISY);
+           if (dp1 != RT_DIR_NULL)
+               db_add_node_to_full_path(p1, dp1);
+           if (dp2 != RT_DIR_NULL)
+               db_add_node_to_full_path(p2, dp2);
+
+           check_walk(diff, msgs, dbip, p1, p2);
+
+           if (dp1 != RT_DIR_NULL)
+               DB_FULL_PATH_POP(p1);
+           if (dp2 != RT_DIR_NULL)
+               DB_FULL_PATH_POP(p2);
+
+           break;
+       case OP_UNION:
+       case OP_INTERSECT:
+       case OP_SUBTRACT:
+       case OP_XOR:
+           check_walk_subtree(diff, msgs, dbip, p1, p2, tp1->tr_b.tb_left, 
tp2->tr_b.tb_left);
+           check_walk_subtree(diff, msgs, dbip, p1, p2, tp1->tr_b.tb_right, 
tp2->tr_b.tb_right);
+           break;
+       default:
+           bu_log("check_walk_subtree: unrecognized operator %d\n", 
tp1->tr_op);
+           bu_bomb("check_walk_subtree: unrecognized operator\n");
+    }
+}
+
+static void
+check_walk(int *diff,
+       struct bu_vls *msgs,
+       struct db_i *dbip,
+       struct db_full_path *p1,
+       struct db_full_path *p2
+               )
+{
+    if ((!p1 && !p2) || !diff || (*diff)) {
+       return; /* nothing to do */
+    }
+
+    if ((!p1 && p2) || (p1 && !p2)) {
+       *diff = 1;
+       return;
+    }
+
+    if (p1->fp_len != p2->fp_len) {
+       *diff = 1;
+       if (msgs) {
+           char *p1s = db_path_to_string(p1);
+           char *p2s = db_path_to_string(p2);
+           bu_vls_printf(msgs, "%s and %s have different lengths - tree 
difference found.\n", p1s, p2s);
+           bu_free(p1s, "p1s");
+           bu_free(p2s, "p2s");
+       }
+       return;
+    }
+
+    struct directory *dp1 = DB_FULL_PATH_CUR_DIR(p1);
+    struct directory *dp2 = DB_FULL_PATH_CUR_DIR(p2);
+
+    if (dp1->d_flags != dp2->d_flags) {
+       *diff = 1;
+       if (msgs) {
+           char *p1s = db_path_to_string(p1);
+           char *p2s = db_path_to_string(p2);
+           bu_vls_printf(msgs, "%s and %s have flag differences.\n", p1s, p2s);
+           bu_free(p1s, "p1s");
+           bu_free(p2s, "p2s");
+       }
+       return;
+    }
+
+    if (dp1->d_flags & RT_DIR_COMB) {
+
+       struct rt_db_internal in1, in2;
+       struct rt_comb_internal *comb1, *comb2;
+
+       if (rt_db_get_internal5(&in1, dp1, dbip, NULL, &rt_uniresource) < 0) {
+           *diff = 1;
+           return;
+       }
+
+       if (rt_db_get_internal5(&in2, dp2, dbip, NULL, &rt_uniresource) < 0) {
+           *diff = 1;
+           return;
+       }
+
+       comb1 = (struct rt_comb_internal *)in1.idb_ptr;
+       comb2 = (struct rt_comb_internal *)in2.idb_ptr;
+       check_walk_subtree(diff, msgs, dbip, p1, p2, comb1->tree, comb2->tree);
+       rt_db_free_internal(&in1);
+       rt_db_free_internal(&in2);
+
+       return;
+    }
+
+    /* If we have two solids, use db_diff_dp */
+    int dr = db_diff_dp(dbip, dbip, dp1, dp2, &dbip->dbi_wdbp->wdb_tol, 
DB_COMPARE_ALL, NULL);
+    if (dr != DIFF_UNCHANGED) {
+       char *p1s = db_path_to_string(p1);
+       char *p2s = db_path_to_string(p2);
+       bu_vls_printf(msgs, "%s and %s differ.\n", p1s, p2s);
+       bu_free(p1s, "p1s");
+       bu_free(p2s, "p2s");
+       *diff = 1;
+    }
+}
+
+
 int
 ged_gdiff_core(struct ged *gedp, int argc, const char *argv[])
 {
@@ -40,7 +194,8 @@
     struct analyze_raydiff_results *results;
     struct bn_tol tol = {BN_TOL_MAGIC, BN_TOL_DIST, BN_TOL_DIST * BN_TOL_DIST, 
1.0e-6, 1.0 - 1.0e-6 };
 
-    int do_diff_raytrace = 1;
+    long verbosity = 0;
+    int structure_diff = 0;
     int view_left = 0;
     int view_right = 0;
     int view_overlap = 0;
@@ -54,7 +209,7 @@
     int ac = argc - 1;
     const char **av = argv+1;
 
-    struct bu_opt_desc d[7];
+    struct bu_opt_desc d[9];
     BU_OPT(d[0], "h", "help",         "",  NULL,            &print_help,   
"Print help.");
     BU_OPT(d[1], "g", "grid-spacing", "#", &bu_opt_fastf_t, &len_tol,      
"Controls spacing of test ray grids (units are mm.)");
     BU_OPT(d[2], "l", "view-left",    "",  NULL,            &view_left,    
"Visualize volumes occurring only in the left object");
@@ -61,7 +216,9 @@
     BU_OPT(d[3], "b", "view-both",    "",  NULL,            &view_overlap, 
"Visualize volumes common to both objects");
     BU_OPT(d[4], "r", "view-right",   "",  NULL,            &view_right,   
"Visualize volumes occurring only in the right object");
     BU_OPT(d[5], "G", "grazing",      "",  NULL,            &grazereport,  
"Report differences in grazing hits");
-    BU_OPT_NULL(d[6]);
+    BU_OPT(d[6], "S", "structure",    "",  NULL,            &structure_diff,  
"Do a diff of tree structures (matrices and objects, ignoring object names.)  
This mode is not raytrace based.");
+    BU_OPT(d[7], "v", "verbosity",      "",  &bu_opt_incr_long, &verbosity,   
"Increase output verbosity.");
+    BU_OPT_NULL(d[8]);
 
     GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
     GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
@@ -73,7 +230,9 @@
 
     if (print_help) {
        char *usage = bu_opt_describe((struct bu_opt_desc *)&d, NULL);
-       bu_vls_printf(gedp->ged_result_str, "Usage: gdiff [opts] left_obj 
right_obj\nOptions:\n%s\nRed segments are those generated\nonly from 
intersections with \"left_obj\" while blue segments represent\nintersections 
unique to \"right_obj\".  White segments represent intersections\ncommon to 
both objects. By default, segments unique to left and right objects are 
displayed.  ", usage);
+       bu_vls_printf(gedp->ged_result_str, "Usage: gdiff [opts] left_obj 
right_obj\n");
+       bu_vls_printf(gedp->ged_result_str, "Options:\n%s\n", usage);
+       bu_vls_printf(gedp->ged_result_str, "When visualizing raytrace based 
diff results, red segments are those generated\nonly from intersections with 
\"left_obj\" while blue segments represent\nintersections unique to 
\"right_obj\".  White segments represent intersections\ncommon to both objects. 
By default, in raytracing mode, segments unique to left and right objects are 
displayed.  ");
        bu_vls_printf(gedp->ged_result_str, "If no tolerance is given, a 
default of 100mm is used.\n\n Be careful of using too fine a grid - finer 
grides will (up to a point) yield better visuals, but too fine a grid can cause 
very long raytracing times.");
        bu_free(usage, "help str");
        return GED_OK;
@@ -89,7 +248,43 @@
        right_obj = av[1];
     }
 
+    if (structure_diff) {
+       int diff = 0;
+       struct bu_vls smsgs = BU_VLS_INIT_ZERO;
+       struct db_full_path *lp, *rp;
+       BU_GET(lp, struct db_full_path);
+       db_full_path_init(lp);
+       BU_GET(rp, struct db_full_path);
+       db_full_path_init(rp);
 
+       struct directory *dp1, *dp2;
+       if ((dp1 = db_lookup(gedp->ged_wdbp->dbip, left_obj, LOOKUP_NOISY)) == 
RT_DIR_NULL) {
+           return GED_ERROR;
+       }
+       if ((dp2 = db_lookup(gedp->ged_wdbp->dbip, right_obj, LOOKUP_NOISY)) == 
RT_DIR_NULL) {
+           return GED_ERROR;
+       }
+
+       db_add_node_to_full_path(lp, dp1);
+       db_add_node_to_full_path(rp, dp2);
+
+       check_walk(&diff, &smsgs, gedp->ged_wdbp->dbip, lp, rp);
+
+       db_free_full_path(lp);
+       BU_PUT(lp, struct db_full_path);
+       db_free_full_path(rp);
+       BU_PUT(rp, struct db_full_path);
+
+       if (bu_vls_strlen(&smsgs))
+           bu_vls_printf(gedp->ged_result_str, "%s\n", bu_vls_cstr(&smsgs));
+
+       bu_vls_free(&smsgs);
+
+       bu_vls_printf(gedp->ged_result_str, "%d", diff);
+
+       return GED_OK;
+    }
+
     /* There are possible convention-based interpretations of 1, 2, 3, 4 and n 
args
      * beyond those used as options.  For the shortest cases, the 
interpretation depends
      * on whether one or two .g files are known:
@@ -124,107 +319,105 @@
      * specified, the argv environments will override use of the "current" .g 
environment.
      */
 
-    if (do_diff_raytrace) {
-       if (db_lookup(gedp->ged_wdbp->dbip, left_obj, LOOKUP_NOISY) == 
RT_DIR_NULL) {
-           return GED_ERROR;
-       }
-       if (db_lookup(gedp->ged_wdbp->dbip, right_obj, LOOKUP_NOISY) == 
RT_DIR_NULL) {
-           return GED_ERROR;
-       }
+    if (db_lookup(gedp->ged_wdbp->dbip, left_obj, LOOKUP_NOISY) == 
RT_DIR_NULL) {
+       return GED_ERROR;
+    }
+    if (db_lookup(gedp->ged_wdbp->dbip, right_obj, LOOKUP_NOISY) == 
RT_DIR_NULL) {
+       return GED_ERROR;
+    }
 
-       /* If we don't have a tolerance, try to guess something sane from the 
bbox */
-       if (NEAR_ZERO(len_tol, RT_LEN_TOL)) {
-           point_t rpp_min, rpp_max;
-           point_t obj_min, obj_max;
-           VSETALL(rpp_min, INFINITY);
-           VSETALL(rpp_max, -INFINITY);
-           ged_get_obj_bounds(gedp, 1, (const char **)&left_obj, 0, obj_min, 
obj_max);
-           VMINMAX(rpp_min, rpp_max, (double *)obj_min);
-           VMINMAX(rpp_min, rpp_max, (double *)obj_max);
-           ged_get_obj_bounds(gedp, 1, (const char **)&right_obj, 0, obj_min, 
obj_max);
-           VMINMAX(rpp_min, rpp_max, (double *)obj_min);
-           VMINMAX(rpp_min, rpp_max, (double *)obj_max);
-           len_tol = DIST_PNT_PNT(rpp_max, rpp_min) * 0.01;
-       }
-       tol.dist = len_tol;
+    /* If we don't have a tolerance, try to guess something sane from the bbox 
*/
+    if (NEAR_ZERO(len_tol, RT_LEN_TOL)) {
+       point_t rpp_min, rpp_max;
+       point_t obj_min, obj_max;
+       VSETALL(rpp_min, INFINITY);
+       VSETALL(rpp_max, -INFINITY);
+       ged_get_obj_bounds(gedp, 1, (const char **)&left_obj, 0, obj_min, 
obj_max);
+       VMINMAX(rpp_min, rpp_max, (double *)obj_min);
+       VMINMAX(rpp_min, rpp_max, (double *)obj_max);
+       ged_get_obj_bounds(gedp, 1, (const char **)&right_obj, 0, obj_min, 
obj_max);
+       VMINMAX(rpp_min, rpp_max, (double *)obj_min);
+       VMINMAX(rpp_min, rpp_max, (double *)obj_max);
+       len_tol = DIST_PNT_PNT(rpp_max, rpp_min) * 0.01;
+    }
+    tol.dist = len_tol;
 
-       analyze_raydiff(&results, gedp->ged_wdbp->dbip, left_obj, right_obj, 
&tol, !grazereport);
+    analyze_raydiff(&results, gedp->ged_wdbp->dbip, left_obj, right_obj, &tol, 
!grazereport);
 
-       /* TODO - may want to integrate with a "regular" diff and report 
intelligently.  Needs
-        * some thought. */
-       if (BU_PTBL_LEN(results->left) > 0 || BU_PTBL_LEN(results->right) > 0) {
-           bu_vls_printf(gedp->ged_result_str, "1");
-       } else {
-           bu_vls_printf(gedp->ged_result_str, "0");
-       }
+    /* TODO - may want to integrate with a "regular" diff and report 
intelligently.  Needs
+     * some thought. */
+    if (BU_PTBL_LEN(results->left) > 0 || BU_PTBL_LEN(results->right) > 0) {
+       bu_vls_printf(gedp->ged_result_str, "1");
+    } else {
+       bu_vls_printf(gedp->ged_result_str, "0");
+    }
 
-       /* For now, graphical output is the main output of this mode, so if we 
don't have any
-        * specifics do left and right */
-       if (!view_left && !view_overlap && !view_right) {
-           view_left = 1;
-           view_right = 1;
-           view_overlap = 0;
-       }
+    /* For now, graphical output is the main output of this mode, so if we 
don't have any
+     * specifics do left and right */
+    if (!view_left && !view_overlap && !view_right) {
+       view_left = 1;
+       view_right = 1;
+       view_overlap = 0;
+    }
 
-       if (view_left || view_overlap || view_right) {
-           /* Visualize the differences */
-           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);
+    if (view_left || view_overlap || view_right) {
+       /* Visualize the differences */
+       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 diff drawing */
-           if (db_lookup(gedp->ged_wdbp->dbip, "diff_visualff", LOOKUP_QUIET) 
!= RT_DIR_NULL)
-               dl_erasePathFromDisplay(gedp, "diff_visualff", 1);
-           if (db_lookup(gedp->ged_wdbp->dbip, "diff_visualff0000", 
LOOKUP_QUIET) != RT_DIR_NULL)
-               dl_erasePathFromDisplay(gedp, "diff_visualff0000", 1);
-           if (db_lookup(gedp->ged_wdbp->dbip, "diff_visualffffff", 
LOOKUP_QUIET) != RT_DIR_NULL)
-               dl_erasePathFromDisplay(gedp, "diff_visualffffff", 1);
+       /* Clear any previous diff drawing */
+       if (db_lookup(gedp->ged_wdbp->dbip, "diff_visualff", LOOKUP_QUIET) != 
RT_DIR_NULL)
+           dl_erasePathFromDisplay(gedp, "diff_visualff", 1);
+       if (db_lookup(gedp->ged_wdbp->dbip, "diff_visualff0000", LOOKUP_QUIET) 
!= RT_DIR_NULL)
+           dl_erasePathFromDisplay(gedp, "diff_visualff0000", 1);
+       if (db_lookup(gedp->ged_wdbp->dbip, "diff_visualffffff", LOOKUP_QUIET) 
!= RT_DIR_NULL)
+           dl_erasePathFromDisplay(gedp, "diff_visualffffff", 1);
 
-           /* Draw left-only lines */
-           if (view_left) {
-               for (i = 0; i < BU_PTBL_LEN(results->left); i++) {
-                   struct diff_seg *dseg = (struct diff_seg 
*)BU_PTBL_GET(results->left, i);
-                   VMOVE(a, dseg->in_pt);
-                   VMOVE(b, dseg->out_pt);
-                   vhead = bn_vlblock_find(vbp, 255, 0, 0); /* should be red */
-                   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);
-               }
+       /* Draw left-only lines */
+       if (view_left) {
+           for (i = 0; i < BU_PTBL_LEN(results->left); i++) {
+               struct diff_seg *dseg = (struct diff_seg 
*)BU_PTBL_GET(results->left, i);
+               VMOVE(a, dseg->in_pt);
+               VMOVE(b, dseg->out_pt);
+               vhead = bn_vlblock_find(vbp, 255, 0, 0); /* should be red */
+               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);
            }
-           /* Draw overlap lines */
-           if (view_overlap) {
-               for (i = 0; i < BU_PTBL_LEN(results->both); i++) {
-                   struct diff_seg *dseg = (struct diff_seg 
*)BU_PTBL_GET(results->both, i);
-                   VMOVE(a, dseg->in_pt);
-                   VMOVE(b, dseg->out_pt);
-                   vhead = bn_vlblock_find(vbp, 255, 255, 255); /* should be 
white */
-                   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);
+       }
+       /* Draw overlap lines */
+       if (view_overlap) {
+           for (i = 0; i < BU_PTBL_LEN(results->both); i++) {
+               struct diff_seg *dseg = (struct diff_seg 
*)BU_PTBL_GET(results->both, i);
+               VMOVE(a, dseg->in_pt);
+               VMOVE(b, dseg->out_pt);
+               vhead = bn_vlblock_find(vbp, 255, 255, 255); /* should be white 
*/
+               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);
 
-               }
            }
-           /* Draw right lines */
-           if (view_right) {
-               for (i = 0; i < BU_PTBL_LEN(results->right); i++) {
-                   struct diff_seg *dseg = (struct diff_seg 
*)BU_PTBL_GET(results->right, i);
-                   VMOVE(a, dseg->in_pt);
-                   VMOVE(b, dseg->out_pt);
-                   vhead = bn_vlblock_find(vbp, 0, 0, 255); /* should be blue 
*/
-                   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);
-               }
+       }
+       /* Draw right lines */
+       if (view_right) {
+           for (i = 0; i < BU_PTBL_LEN(results->right); i++) {
+               struct diff_seg *dseg = (struct diff_seg 
*)BU_PTBL_GET(results->right, i);
+               VMOVE(a, dseg->in_pt);
+               VMOVE(b, dseg->out_pt);
+               vhead = bn_vlblock_find(vbp, 0, 0, 255); /* should be blue */
+               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, "diff_visual", 0);
+       _ged_cvt_vlblock_to_solids(gedp, vbp, "diff_visual", 0);
 
-           bn_vlist_cleanup(&local_vlist);
-           bn_vlblock_free(vbp);
-       }
-       analyze_raydiff_results_free(results);
+       bn_vlist_cleanup(&local_vlist);
+       bn_vlblock_free(vbp);
     }
+    analyze_raydiff_results_free(results);
 
     return GED_OK;
 }

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