BRL-CAD
db_diff.c
Go to the documentation of this file.
1 /* D B _ D I F F . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1998-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @file db_diff.c
21  *
22  * Routines to determine the differences between two BRL-CAD databases.
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <stdlib.h>
29 #include <math.h>
30 #include <ctype.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <string.h>
34 #include <errno.h>
35 #include "bio.h"
36 
37 #include "tcl.h"
38 
39 #include "vmath.h"
40 #include "nmg.h"
41 #include "rtgeom.h"
42 #include "raytrace.h"
43 #include "rt/db_diff.h"
44 
45 /* TODO - there has to be a better way to do this. Seems like overkill to define
46  * a functab function, but this is way too fragile */
47 HIDDEN int
49  if (type >= ID_MAXIMUM) return 0;
50  switch (type) {
51  case ID_NULL :/**< @brief Unused */
52  return 0;
53  break;
54  case ID_TOR :/**< @brief Toroid */
55  return sizeof(struct rt_tor_internal);
56  break;
57  case ID_TGC :/**< @brief Generalized Truncated General Cone */
58  return sizeof(struct rt_tgc_internal);
59  break;
60  case ID_ELL :/**< @brief Ellipsoid */
61  return sizeof(struct rt_ell_internal);
62  break;
63  case ID_ARB8 :/**< @brief Generalized ARB. V + 7 vectors */
64  return sizeof(struct rt_arb_internal);
65  break;
66  case ID_ARS :/**< @brief ARS */
67  return sizeof(struct rt_ars_internal);
68  break;
69  case ID_HALF :/**< @brief Half-space */
70  return sizeof(struct rt_half_internal);
71  break;
72  case ID_REC :/**< @brief Right Elliptical Cylinder [TGC special] */
73  return sizeof(struct rt_tgc_internal);
74  break;
75  case ID_POLY :/**< @brief Polygonal faceted object */
76  return sizeof(struct rt_pg_face_internal);
77  break;
78  case ID_BSPLINE :/**< @brief B-spline object */
79  return sizeof(struct rt_nurb_internal);
80  break;
81  case ID_SPH :/**< @brief Sphere */
82  return sizeof(struct rt_ell_internal);
83  break;
84  case ID_NMG :/**< @brief n-Manifold Geometry solid */
85  return sizeof(struct model);
86  break;
87  case ID_EBM :/**< @brief Extruded bitmap solid */
88  return sizeof(struct rt_ebm_internal);
89  break;
90  case ID_VOL :/**< @brief 3-D Volume */
91  return sizeof(struct rt_vol_internal);
92  break;
93  case ID_ARBN :/**< @brief ARB with N faces */
94  return sizeof(struct rt_arbn_internal);
95  break;
96  case ID_PIPE :/**< @brief Pipe (wire) solid */
97  return sizeof(struct rt_pipe_internal);
98  break;
99  case ID_PARTICLE :/**< @brief Particle system solid */
100  return sizeof(struct rt_part_internal);
101  break;
102  case ID_RPC :/**< @brief Right Parabolic Cylinder */
103  return sizeof(struct rt_rpc_internal);
104  break;
105  case ID_RHC :/**< @brief Right Hyperbolic Cylinder */
106  return sizeof(struct rt_rhc_internal);
107  break;
108  case ID_EPA :/**< @brief Elliptical Paraboloid */
109  return sizeof(struct rt_epa_internal);
110  break;
111  case ID_EHY :/**< @brief Elliptical Hyperboloid */
112  return sizeof(struct rt_ehy_internal);
113  break;
114  case ID_ETO :/**< @brief Elliptical Torus */
115  return sizeof(struct rt_eto_internal);
116  break;
117  case ID_GRIP :/**< @brief Pseudo Solid Grip */
118  return sizeof(struct rt_grip_internal);
119  break;
120  case ID_JOINT :/**< @brief Pseudo Solid/Region Joint */
121  return 0;
122  break;
123  case ID_HF :/**< @brief Height Field */
124  return sizeof(struct rt_hf_internal);
125  break;
126  case ID_DSP :/**< @brief Displacement map */
127  return sizeof(struct rt_dsp_internal);
128  break;
129  case ID_SKETCH :/**< @brief 2D sketch */
130  return sizeof(struct rt_sketch_internal);
131  break;
132  case ID_EXTRUDE :/**< @brief Solid of extrusion */
133  return sizeof(struct rt_extrude_internal);
134  break;
135  case ID_SUBMODEL :/**< @brief Instanced submodel */
136  return sizeof(struct rt_submodel_internal);
137  break;
138  case ID_CLINE :/**< @brief FASTGEN4 CLINE solid */
139  return sizeof(struct rt_cline_internal);
140  break;
141  case ID_BOT :/**< @brief Bag o' triangles */
142  return sizeof(struct rt_bot_internal);
143  break;
144  case ID_COMBINATION:/**< @brief Combination Record */
145  return sizeof(struct rt_comb_internal);
146  break;
147  case ID_BINUNIF :/**< @brief Uniform-array binary */
148  return sizeof(struct rt_binunif_internal);
149  break;
150  case ID_CONSTRAINT :/**< @brief Constraint object */
151  return sizeof(struct rt_constraint_internal);
152  break;
153  case ID_SUPERELL :/**< @brief Superquadratic ellipsoid */
154  return sizeof(struct rt_superell_internal);
155  break;
156  case ID_METABALL :/**< @brief Metaball */
157  return sizeof(struct rt_metaball_internal);
158  break;
159  case ID_BREP :/**< @brief B-rep object */
160  return sizeof(struct rt_brep_internal);
161  break;
162  case ID_HYP :/**< @brief Hyperboloid of one sheet */
163  return sizeof(struct rt_hyp_internal);
164  break;
165  case ID_REVOLVE :/**< @brief Solid of Revolution */
166  return sizeof(struct rt_revolve_internal);
167  break;
168  case ID_PNTS :/**< @brief Collection of Points */
169  return sizeof(struct rt_pnts_internal);
170  break;
171  case ID_ANNOTATION :/**< @brief Annotation */
172  return sizeof(struct rt_annotation_internal);
173  break;
174  case ID_HRT :/**< @brief Heart */
175  return sizeof(struct rt_hrt_internal);
176  break;
177  default:
178  return 0;
179  break;
180  }
181  return 0;
182 }
183 
184 /* Exposed as private function to librt, but not (currently) beyond librt -
185  * see librt_private.h */
186 int
187 tcl_list_to_avs(const char *tcl_list, struct bu_attribute_value_set *avs, int offset)
188 {
189  int i = 0;
190  int list_c = 0;
191  const char **listv = (const char **)NULL;
192 
193  if (Tcl_SplitList(NULL, tcl_list, &list_c, (const char ***)&listv) != TCL_OK) {
194  return -1;
195  }
196 
197  if (!BU_AVS_IS_INITIALIZED(avs)) BU_AVS_INIT(avs);
198 
199  if (!list_c) {
200  Tcl_Free((char *)listv);
201  return 0;
202  }
203 
204  if (list_c > 2) {
205  for (i = offset; i < list_c; i += 2) {
206  (void)bu_avs_add(avs, listv[i], listv[i+1]);
207  }
208  } else {
209  return -1;
210  }
211 
212  Tcl_Free((char *)listv);
213  return 0;
214 }
215 
216 /* TODO - this should be a function somewhere, is it already? */
217 HIDDEN const char *
218 arb_type_to_str(int type) {
219  switch (type) {
220  case 4:
221  return "arb4";
222  break;
223  case 5:
224  return "arb5";
225  break;
226  case 6:
227  return "arb6";
228  break;
229  case 7:
230  return "arb7";
231  break;
232  case 8:
233  return "arb8";
234  break;
235  default:
236  return NULL;
237  break;
238  }
239  return NULL;
240 }
241 HIDDEN const char *
242 type_to_str(const struct rt_db_internal *obj, int arb_type) {
243  if (arb_type) return arb_type_to_str(arb_type);
244  return obj->idb_meth->ft_label;
245 }
246 
247 void
248 diff_init_avp(struct diff_avp *attr_result)
249 {
250  if (!attr_result) return;
251  attr_result->name = NULL;
252  attr_result->left_value = NULL;
253  attr_result->ancestor_value = NULL;
254  attr_result->right_value = NULL;
255 }
256 
257 void
258 diff_free_avp(struct diff_avp *attr_result)
259 {
260  if (!attr_result) return;
261  if (attr_result->name) bu_free(attr_result->name, "free diff_avp name");
262  if (attr_result->left_value) bu_free(attr_result->left_value, "free diff_avp left_value");
263  if (attr_result->ancestor_value) bu_free(attr_result->ancestor_value, "free diff_avp ancestor_value");
264  if (attr_result->right_value) bu_free(attr_result->right_value, "free diff_avp right_value");
265 }
266 
267 void
268 diff_init_result(struct diff_result *result, const struct bn_tol *curr_diff_tol, const char *obj_name)
269 {
270  if (!result) return;
271  if (obj_name) {
272  result->obj_name = bu_strdup(obj_name);
273  } else {
274  result->obj_name = NULL;
275  }
276  result->dp_left = RT_DIR_NULL;
277  result->dp_ancestor = RT_DIR_NULL;
278  result->dp_right = RT_DIR_NULL;
279  result->param_state = DIFF_EMPTY;
280  result->attr_state = DIFF_EMPTY;
281  BU_GET(result->diff_tol, struct bn_tol);
282  if (curr_diff_tol) {
283  (result)->diff_tol->magic = BN_TOL_MAGIC;
284  (result)->diff_tol->dist = curr_diff_tol->dist;
285  (result)->diff_tol->dist_sq = curr_diff_tol->dist_sq;
286  (result)->diff_tol->perp = curr_diff_tol->perp;
287  (result)->diff_tol->para = curr_diff_tol->para;
288  } else {
289  BN_TOL_INIT(result->diff_tol);
290  }
291  BU_GET(result->param_diffs, struct bu_ptbl);
292  BU_GET(result->attr_diffs, struct bu_ptbl);
293  BU_PTBL_INIT(result->param_diffs);
294  BU_PTBL_INIT(result->attr_diffs);
295 }
296 
297 
298 void
300 {
301  unsigned int i = 0;
302  if (result->obj_name) {
303  bu_free(result->obj_name, "free name copy in diff result");
304  }
305  BU_PUT(result->diff_tol, struct bn_tol);
306  for (i = 0; i < BU_PTBL_LEN(result->param_diffs); i++) {
307  struct diff_avp *avp = (struct diff_avp *)BU_PTBL_GET(result->param_diffs, i);
308  diff_free_avp(avp);
309  BU_PUT(avp, struct diff_avp);
310  }
311  bu_ptbl_free(result->param_diffs);
312  BU_PUT(result->param_diffs, struct bu_ptbl);
313  for (i = 0; i < BU_PTBL_LEN(result->attr_diffs); i++) {
314  struct diff_avp *avp = (struct diff_avp *)BU_PTBL_GET(result->attr_diffs, i);
315  diff_free_avp(avp);
316  BU_PUT(avp, struct diff_avp);
317  }
318  bu_ptbl_free(result->attr_diffs);
319  BU_PUT(result->attr_diffs, struct bu_ptbl);
320 }
321 
322 HIDDEN int
323 avpp_val_compare(const char *val1, const char *val2, const struct bn_tol *diff_tol)
324 {
325  /* We need to look for numbers to do tolerance based comparisons */
326  int num_compare = 1;
327  /*int color_compare = 1;*/
328  int pnt_compare = 1;
329  double dval1, dval2;
330  /*int c1val1, c1val2, c1val3;
331  int c2val1, c2val2, c2val3;*/
332  float p1val1, p1val2, p1val3;
333  float p2val1, p2val2, p2val3;
334  char *endptr;
335  /* Don't try a numerical comparison unless the strings differ -
336  * numerical attempts when they are not needed can introduce
337  * invalid changes */
338  int retval = BU_STR_EQUAL(val1, val2);
339 
340  if (!retval) {
341  /* First, check for individual numbers */
342  errno = 0;
343  dval1 = strtod(val1, &endptr);
344  if (errno == EINVAL || *endptr != '\0') num_compare--;
345  errno = 0;
346  dval2 = strtod(val2, &endptr);
347  if (errno == EINVAL || *endptr != '\0') num_compare--;
348  if (num_compare == 1) {return NEAR_EQUAL(dval1, dval2, diff_tol->dist);}
349 
350  /* If we didn't find numbers, try for points (3 floating point numbers) */
351  if (sscanf(val1, "%f %f %f", &p1val1, &p1val2, &p1val3) == 3) pnt_compare--;
352  if (sscanf(val2, "%f %f %f", &p2val1, &p2val2, &p2val3) == 3) pnt_compare--;
353 
354  if (pnt_compare == -1) {
355  vect_t v1, v2;
356  VSET(v1, p1val1, p1val2, p1val3);
357  VSET(v2, p2val1, p2val2, p2val3);
358  return VNEAR_EQUAL(v1, v2, diff_tol->dist);
359  }
360  }
361  return retval;
362 }
363 
364 int
365 db_avs_diff(const struct bu_attribute_value_set *left_set,
366  const struct bu_attribute_value_set *right_set,
367  const struct bn_tol *diff_tol,
368  int (*add_func)(const char *attr_name, const char *attr_val, void *data),
369  int (*del_func)(const char *attr_name, const char *attr_val, void *data),
370  int (*chgd_func)(const char *attr_name, const char *attr_val_left, const char *attr_val_right, void *data),
371  int (*unchgd_func)(const char *attr_name, const char *attr_val, void *data),
372  void *client_data)
373 {
374  int state = DIFF_EMPTY;
375  struct bu_attribute_value_pair *avp;
376  for (BU_AVS_FOR(avp, left_set)) {
377  const char *val2 = bu_avs_get(right_set, avp->name);
378  if (!val2) {
379  if (del_func) {state |= del_func(avp->name, avp->value, client_data);}
380  } else {
381  if (avpp_val_compare(avp->value, val2, diff_tol)) {
382  if (unchgd_func) {state |= unchgd_func(avp->name, avp->value, client_data);}
383  } else {
384  if (chgd_func) {state |= chgd_func(avp->name, avp->value, val2, client_data);}
385  }
386  }
387  }
388  for (BU_AVS_FOR(avp, right_set)) {
389  const char *val1 = bu_avs_get(left_set, avp->name);
390  if (!val1) {
391  if (add_func) {state |= add_func(avp->name, avp->value, client_data);}
392  }
393  }
394  return state;
395 }
396 
397 
398 HIDDEN int
399 db_diff_external(const struct bu_external *ext1, const struct bu_external *ext2)
400 {
401  if (ext1->ext_nbytes != ext2->ext_nbytes) {
402  return 1;
403  }
404  if (memcmp((void *)ext1->ext_buf, (void *)ext2->ext_buf, ext1->ext_nbytes)) {
405  return 1;
406  }
407  return 0;
408 }
409 
411  const char *name;
412  int bin_obj;
415  void *idb_ptr;
418 };
419 
420 HIDDEN void
421 get_diff_components(struct diff_elements *el, const struct db_i *dbip, const struct directory *dp)
422 {
423  el->name = NULL;
424  el->idb_ptr = NULL;
425  el->bin_params = 0;
426  el->bin_obj = 0;
427  el->intern = NULL;
428 
429  BU_GET(el->attrs, struct bu_attribute_value_set);
430  BU_AVS_INIT(el->attrs);
431  BU_GET(el->params, struct bu_attribute_value_set);
432  BU_AVS_INIT(el->params);
433 
434  if (!dp) return;
435 
436  el->name = dp->d_namep;
437 
438  /* Deal with attribute-only objects, since they're "special" */
439  if (dp->d_major_type == DB5_MAJORTYPE_ATTRIBUTE_ONLY) {
440  struct bu_external dp_ext;
441  struct db5_raw_internal dp_raw;
442  BU_EXTERNAL_INIT(&dp_ext);
443  if (db_get_external(&dp_ext, dp, dbip) < 0 || db5_get_raw_internal_ptr(&dp_raw, dp_ext.ext_buf) == NULL) {
444  bu_free_external(&dp_ext);
445  el->bin_obj = 1;
446  return;
447  }
448  /* Parse out the attributes */
449  if (db5_import_attributes(el->attrs, &dp_raw.attributes) < 0) {
450  bu_free_external(&dp_ext);
451  el->bin_obj = 1;
452  return;
453  }
454  bu_free_external(&dp_ext);
455  return;
456  }
457 
458  /* Now deal with more normal objects */
459  BU_GET(el->intern, struct rt_db_internal);
461  if (rt_db_get_internal(el->intern, dp, dbip, (fastf_t *)NULL, &rt_uniresource) < 0) {
462  /* Arrgh - No internal representation */
464  BU_PUT(el->intern, struct rt_db_internal);
465  el->intern = NULL;
466  el->bin_obj = 1;
467  return;
468  } else {
469  struct bu_vls s_tcl = BU_VLS_INIT_ZERO;
470  int have_tcl = 1;
471 
472  el->idb_ptr = el->intern->idb_ptr;
473 
474  /* object type isn't a normal parameter attribute, so add it as such */
475  if (el->intern->idb_minor_type == DB5_MINORTYPE_BRLCAD_ARB8) {
476  struct bn_tol arb_tol = {BN_TOL_MAGIC, BN_TOL_DIST, BN_TOL_DIST * BN_TOL_DIST, 1e-6, 1.0 - 1e-6 };
477  bu_avs_add(el->params, "DB5_MINORTYPE", type_to_str(el->intern, rt_arb_std_type(el->intern, &arb_tol)));
478  } else {
479  bu_avs_add(el->params, "DB5_MINORTYPE", el->intern->idb_meth->ft_label);
480  }
481 
482  /* Convert the rest of the params to attributes, if possible */
483  bu_vls_trunc(&s_tcl, 0);
484  if (el->intern->idb_meth->ft_get(&s_tcl, el->intern, NULL) == BRLCAD_ERROR) have_tcl = 0;
485  if (!have_tcl || tcl_list_to_avs(bu_vls_addr(&s_tcl), el->params, 1)) have_tcl = 0;
486  if (!have_tcl) {
487  el->bin_params = 1;
488  }
489  bu_vls_free(&s_tcl);
490 
491  /* Pick up the extra attributes */
492  if (el->intern->idb_avs.magic == BU_AVS_MAGIC) {
493  bu_avs_merge(el->attrs, &(el->intern->idb_avs));
494  }
495 
496  }
497 }
498 
499 HIDDEN void
501 {
502  bu_avs_free(el->attrs);
503  bu_avs_free(el->params);
504  BU_PUT(el->attrs, struct bu_attribute_value_set);
505  BU_PUT(el->params, struct bu_attribute_value_set);
506  if (el->intern) {
508  BU_PUT(el->intern, struct rt_db_internal);
509  }
510 }
511 
512 HIDDEN int
513 diff_dp_attr_add(const char *attr_name, const char *attr_val, void *data)
514 {
515  struct bu_ptbl *diffs = (struct bu_ptbl *)data;
516  struct diff_avp *avp;
517  BU_GET(avp, struct diff_avp);
518  diff_init_avp(avp);
519  avp->state = DIFF_ADDED;
520  avp->name = bu_strdup(attr_name);
521  avp->right_value = bu_strdup(attr_val);
522  bu_ptbl_ins(diffs, (long *)avp);
523  return avp->state;
524 }
525 
526 HIDDEN int
527 diff_dp_attr_del(const char *attr_name, const char *attr_val, void *data)
528 {
529  struct bu_ptbl *diffs = (struct bu_ptbl *)data;
530  struct diff_avp *avp;
531  BU_GET(avp, struct diff_avp);
532  diff_init_avp(avp);
533  avp->state = DIFF_REMOVED;
534  avp->name = bu_strdup(attr_name);
535  avp->left_value = bu_strdup(attr_val);
536  bu_ptbl_ins(diffs, (long *)avp);
537  return avp->state;
538 }
539 
540 HIDDEN int
541 diff_dp_attr_chgd(const char *attr_name, const char *attr_val_left, const char *attr_val_right, void *data)
542 {
543  struct bu_ptbl *diffs = (struct bu_ptbl *)data;
544  struct diff_avp *avp;
545  BU_GET(avp, struct diff_avp);
546  diff_init_avp(avp);
547  avp->state = DIFF_CHANGED;
548  avp->name = bu_strdup(attr_name);
549  avp->left_value = bu_strdup(attr_val_left);
550  avp->right_value = bu_strdup(attr_val_right);
551  bu_ptbl_ins(diffs, (long *)avp);
552  return avp->state;
553 }
554 
555 HIDDEN int
556 diff_dp_attr_unchgd(const char *attr_name, const char *attr_val, void *data)
557 {
558  struct bu_ptbl *diffs = (struct bu_ptbl *)data;
559  struct diff_avp *avp;
560  BU_GET(avp, struct diff_avp);
561  diff_init_avp(avp);
562  avp->state = DIFF_UNCHANGED;
563  avp->name = bu_strdup(attr_name);
564  avp->left_value = bu_strdup(attr_val);
565  avp->right_value = bu_strdup(attr_val);
566  bu_ptbl_ins(diffs, (long *)avp);
567  return avp->state;
568 }
569 
570 int
571 db_diff_dp(const struct db_i *left,
572  const struct db_i *right,
573  const struct directory *left_dp,
574  const struct directory *right_dp,
575  const struct bn_tol *diff_tol,
576  db_compare_criteria_t flags,
577  struct diff_result *ext_result)
578 {
579  int state = DIFF_EMPTY;
580 
581  struct diff_elements left_components;
582  struct diff_elements right_components;
583 
584  struct diff_result *result = NULL;
585 
586  if (!left_dp && !right_dp) return -1;
587  if (!diff_tol) return -1;
588 
589  /* If we aren't populating a result struct for the
590  * caller, use a local copy to keep the code simple */
591  if (!ext_result) {
592  BU_GET(result, struct diff_result);
593  diff_init_result(result, diff_tol, "tmp");
594  } else {
595  result = ext_result;
596  }
597 
598  if (left_dp) result->dp_left = left_dp;
599  if (right_dp) result->dp_right = right_dp;
600 
601  get_diff_components(&left_components, left, left_dp);
602  get_diff_components(&right_components, right, right_dp);
603 
604  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_PARAM) {
605 
606  result->param_state |= db_avs_diff(left_components.params, right_components.params, diff_tol, diff_dp_attr_add, diff_dp_attr_del, diff_dp_attr_chgd, diff_dp_attr_unchgd, (void *)(result->param_diffs));
607  /*compare the idb_ptr memory, if the types are the same.*/
608  if (left_components.bin_params && right_components.bin_params && left_components.idb_ptr && right_components.idb_ptr) {
609  if (left_components.intern->idb_minor_type == right_components.intern->idb_minor_type) {
610  int memsize = rt_intern_struct_size(left_components.intern->idb_minor_type);
611  if (memcmp((void *)left_components.idb_ptr, (void *)right_components.idb_ptr, memsize)) {
612  /* If we didn't pick up differences in the avs comparison, we need to use this result to flag a parameter difference */
613  if (result->param_state == DIFF_UNCHANGED || result->param_state == DIFF_EMPTY) result->param_state |= DIFF_CHANGED;
614  } else {
615  if (result->param_state == DIFF_EMPTY) result->param_state |= DIFF_UNCHANGED;
616  }
617  }
618  }
619  }
620 
621  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_ATTRS) {
622  result->attr_state |= db_avs_diff(left_components.attrs, right_components.attrs, diff_tol, diff_dp_attr_add, diff_dp_attr_del, diff_dp_attr_chgd, diff_dp_attr_unchgd, (void *)(result->attr_diffs));
623  }
624 
625  free_diff_components(&left_components);
626  free_diff_components(&right_components);
627 
628  state |= result->param_state;
629  state |= result->attr_state;
630 
631  if (!ext_result) {
632  diff_free_result(result);
633  BU_PUT(result, struct diff_result);
634  }
635 
636  return state;
637 }
638 
639 int
640 db_diff(const struct db_i *dbip1,
641  const struct db_i *dbip2,
642  const struct bn_tol *diff_tol,
643  db_compare_criteria_t flags,
644  struct bu_ptbl *results)
645 {
646  int state = DIFF_EMPTY;
647  struct directory *dp1, *dp2;
648 
649  /* look at all objects in this database */
650  FOR_ALL_DIRECTORY_START(dp1, dbip1) {
651  struct bu_external ext1, ext2;
652  int extern_state = DIFF_UNCHANGED;
653  struct diff_result *result;
654  BU_GET(result, struct diff_result);
655  diff_init_result(result, diff_tol, dp1->d_namep);
656 
657  /* determine the status of this object in the other database */
658  dp2 = db_lookup(dbip2, dp1->d_namep, 0);
659 
660  /* If we're checking everything, we want a sanity check to make sure we spot it when the objects differ */
661  if (flags == DB_COMPARE_ALL && dp1 != RT_DIR_NULL && dp1->d_major_type != DB5_MAJORTYPE_ATTRIBUTE_ONLY && dp2 != RT_DIR_NULL && dp2->d_major_type != DB5_MAJORTYPE_ATTRIBUTE_ONLY) {
662  if (db_get_external(&ext1, dp1, dbip1) || db_get_external(&ext2, dp2, dbip2)) {
663  bu_log("Warning - Error getting bu_external form when comparing %s and %s\n", dp1->d_namep, dp2->d_namep);
664  } else {
665  if (db_diff_external(&ext1, &ext2)) {extern_state = DIFF_CHANGED;}
666  }
667  bu_free_external(&ext1);
668  bu_free_external(&ext2);
669  }
670 
671  /* Do internal diffs */
672  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_PARAM) {
673  state |= db_diff_dp(dbip1, dbip2, dp1, dp2, diff_tol, DB_COMPARE_PARAM, result);
674  }
675  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_ATTRS) {
676  state |= db_diff_dp(dbip1, dbip2, dp1, dp2, diff_tol, DB_COMPARE_ATTRS, result);
677  }
678  if (flags == DB_COMPARE_ALL && state == DIFF_UNCHANGED && extern_state == DIFF_CHANGED) {
679  bu_log("Warning - internal comparison and bu_external comparison disagree when comparing %s and %s\n", dp1->d_namep, dp2->d_namep);
680 
681  }
682 
683  if (results) {
684  bu_ptbl_ins(results, (long *)result);
685  } else {
686  diff_free_result(result);
687  BU_PUT(result, struct diff_result);
688  }
689 
691 
692  /* now look for objects in the other database that aren't here */
693  FOR_ALL_DIRECTORY_START(dp2, dbip2) {
694 
695  /* determine the status of this object in the other database */
696  dp1 = db_lookup(dbip1, dp2->d_namep, 0);
697 
698  /* By this point, any differences will be additions */
699  if (dp1 == RT_DIR_NULL) {
700  struct diff_result *result;
701  BU_GET(result, struct diff_result);
702  diff_init_result(result, diff_tol, dp2->d_namep);
703 
704  /* Do internal diffs */
705  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_PARAM) {
706  state |= db_diff_dp(dbip1, dbip2, dp1, dp2, diff_tol, DB_COMPARE_PARAM, result);
707  }
708  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_ATTRS) {
709  state |= db_diff_dp(dbip1, dbip2, dp1, dp2, diff_tol, DB_COMPARE_ATTRS, result);
710  }
711 
712  if (results) {
713  bu_ptbl_ins(results, (long *)result);
714  } else {
715  diff_free_result(result);
716  BU_PUT(result, struct diff_result);
717  }
718  }
719 
721 
722  return state;
723 }
724 
725 int
726 db_avs_diff3(const struct bu_attribute_value_set *left_set,
727  const struct bu_attribute_value_set *ancestor_set,
728  const struct bu_attribute_value_set *right_set,
729  const struct bn_tol *diff_tol,
730  int (*add_func)(const char *attr_name, const char *attr_val_left, const char *attr_val_right, void *data),
731  int (*del_func)(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data),
732  int (*chgd_func)(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data),
733  int (*conflict_func)(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data),
734  int (*unchgd_func)(const char *attr_name, const char *attr_val, void *data),
735  void *client_data)
736 {
737  int state = DIFF_EMPTY;
738  struct bu_attribute_value_pair *avp;
739  for (BU_AVS_FOR(avp, ancestor_set)) {
740  const char *val_ancestor = bu_avs_get(ancestor_set, avp->name);
741  const char *val_left = bu_avs_get(left_set, avp->name);
742  const char *val_right = bu_avs_get(right_set, avp->name);
743 
744  /* The possibilities are:
745  *
746  * (!val_left && !val_right) && val_ancestor
747  * (val_left && !val_right) && (val_ancestor == val_left)
748  * (val_left && !val_right) && (val_ancestor != val_left)
749  * (!val_left && val_right) && (val_ancestor == val_right)
750  * (!val_left && val_right) && (val_ancestor != val_right)
751  * (val_left == val_right) && (val_ancestor == val_left)
752  * (val_left == val_right) && (val_ancestor != val_left)
753  * (val_left != val_right) && (val_ancestor == val_left)
754  * (val_left != val_right) && (val_ancestor == val_right)
755  * (val_left != val_right) && (val_ancestor != val_left && val_ancestor != val_right)
756  */
757 
758  if (!val_left || !val_right) {
759  /* Removed from both - no conflict, nothing to merge */
760  if ((!val_left && !val_right) && val_ancestor) {
761  if (del_func) {state |= del_func(avp->name, NULL, avp->value, NULL, client_data);}
762  }
763 
764  /* Removed from right_set only, left_set not changed - no conflict,
765  * right_set removal wins and left_set is not merged */
766  if ((val_left && !val_right) && avpp_val_compare(val_ancestor, val_left, diff_tol)) {
767  if (del_func) {state |= del_func(avp->name, val_left, avp->value, NULL, client_data);}
768  }
769 
770  /* Removed from right_set only, left_set changed - conflict */
771  if ((val_left && !val_right) && !avpp_val_compare(val_ancestor, val_left, diff_tol)) {
772  if (conflict_func) {state |= conflict_func(avp->name, val_left, val_ancestor, val_right, client_data);}
773  }
774 
775  /* Removed from left_set only, right_set not changed - no conflict,
776  * left_set change wins and right_set not merged */
777  if ((!val_left && val_right) && avpp_val_compare(val_ancestor, val_right, diff_tol)) {
778  if (del_func) {state |= del_func(avp->name, NULL, avp->value, val_right, client_data);}
779  }
780 
781  /* Removed from left_set only, right_set changed - conflict,
782  * merge defaults to preserving information */
783  if ((!val_left && val_right) && !avpp_val_compare(val_ancestor, val_right, diff_tol)) {
784  if (conflict_func) {state |= conflict_func(avp->name, val_left, val_ancestor, val_right, client_data);}
785  }
786  } else {
787 
788  /* All values equal, unchanged and merged */
789  if (avpp_val_compare(val_left, val_right, diff_tol) && avpp_val_compare(val_ancestor, val_left, diff_tol)) {
790  if (unchgd_func) {state |= unchgd_func(avp->name, avp->value, client_data);}
791  }
792  /* Identical change to both - changed and merged */
793  if (avpp_val_compare(val_left, val_right, diff_tol) && !avpp_val_compare(val_ancestor, val_left, diff_tol)) {
794  if (chgd_func) {state |= chgd_func(avp->name, val_left, val_ancestor, val_right, client_data);}
795  }
796  /* val_right changed, val_left not changed - val_right change wins and is merged */
797  if (!avpp_val_compare(val_left, val_right, diff_tol) && avpp_val_compare(val_ancestor, val_left, diff_tol)) {
798  if (chgd_func) {state |= chgd_func(avp->name, val_left, val_ancestor, val_right, client_data);}
799  }
800  /* val_left changed, val_right not changed - val_left change wins and is merged */
801  if (!avpp_val_compare(val_left, val_right, diff_tol) && avpp_val_compare(val_ancestor, val_right, diff_tol)) {
802  if (chgd_func) {state |= chgd_func(avp->name, val_left, val_ancestor, val_right, client_data);}
803  }
804  /* val_left and val_right changed and incompatible - conflict,
805  * merge adds conflict a/v pairs */
806  if (!avpp_val_compare(val_left, val_right, diff_tol) && !avpp_val_compare(val_ancestor, val_left, diff_tol) && !avpp_val_compare(val_ancestor, val_right, diff_tol)) {
807  if (conflict_func) {state |= conflict_func(avp->name, val_left, val_ancestor, val_right, client_data);}
808  }
809  }
810  }
811 
812  /* Now do left_set - anything in ancestor has already been handled */
813  for (BU_AVS_FOR(avp, left_set)) {
814  const char *val_ancestor = bu_avs_get(ancestor_set, avp->name);
815  if (!val_ancestor) {
816  const char *val_left = bu_avs_get(left_set, avp->name);
817  const char *val_right = bu_avs_get(right_set, avp->name);
818  /* (val_left && !val_right) */
819  if (val_left && !val_right) {
820  if (add_func) {state |= add_func(avp->name, val_left, NULL, client_data);}
821  } else {
822  int have_same_val = avpp_val_compare(val_left,val_right, diff_tol);
823  /* (val_left == val_right) */
824  if (have_same_val) {
825  if (add_func) {state |= add_func(avp->name, val_left, val_right, client_data);}
826  } else {
827  /* (val_left != val_right) */
828  if (conflict_func) {state |= conflict_func(avp->name, val_left, NULL, val_right, client_data);}
829  }
830  }
831  }
832  }
833 
834  /* Last but not least, right_set - anything in ancestor and/or left_set has already been handled */
835  for (BU_AVS_FOR(avp, right_set)) {
836  if (!bu_avs_get(ancestor_set, avp->name) && !bu_avs_get(left_set, avp->name)) {
837  if (add_func) {state |= add_func(avp->name, NULL, avp->value, client_data);}
838  }
839  }
840 
841  return state;
842 }
843 
844 HIDDEN int
845 diff3_dp_attr_add(const char *attr_name, const char *attr_val_left, const char *attr_val_right, void *data)
846 {
847  struct bu_ptbl *diffs = (struct bu_ptbl *)data;
848  struct diff_avp *avp;
849  BU_GET(avp, struct diff_avp);
850  diff_init_avp(avp);
851  avp->name = bu_strdup(attr_name);
852  avp->state = DIFF_ADDED;
853  if (attr_val_left) avp->left_value = bu_strdup(attr_val_left);
854  if (attr_val_right) avp->right_value = bu_strdup(attr_val_right);
855  bu_ptbl_ins(diffs, (long *)avp);
856  return avp->state;
857 }
858 
859 HIDDEN int
860 diff3_dp_attr_del(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data)
861 {
862  struct bu_ptbl *diffs = (struct bu_ptbl *)data;
863  struct diff_avp *avp;
864  BU_GET(avp, struct diff_avp);
865  diff_init_avp(avp);
866  avp->name = bu_strdup(attr_name);
867  avp->state = DIFF_REMOVED;
868  avp->ancestor_value = bu_strdup(attr_val_ancestor);
869  if (attr_val_right)
870  avp->right_value = bu_strdup(attr_val_right);
871  if (attr_val_left)
872  avp->left_value = bu_strdup(attr_val_left);
873  bu_ptbl_ins(diffs, (long *)avp);
874  return avp->state;
875 }
876 
877 HIDDEN int
878 diff3_dp_attr_chgd(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data)
879 {
880  struct bu_ptbl *diffs = (struct bu_ptbl *)data;
881  struct diff_avp *avp;
882  BU_GET(avp, struct diff_avp);
883  diff_init_avp(avp);
884  avp->name = bu_strdup(attr_name);
885  avp->state = DIFF_CHANGED;
886  avp->ancestor_value = bu_strdup(attr_val_ancestor);
887  avp->right_value = bu_strdup(attr_val_right);
888  avp->left_value = bu_strdup(attr_val_left);
889  bu_ptbl_ins(diffs, (long *)avp);
890  return avp->state;
891 }
892 
893 HIDDEN int
894 diff3_dp_attr_conflict(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data)
895 {
896  struct bu_ptbl *diffs = (struct bu_ptbl *)data;
897  struct diff_avp *avp;
898  BU_GET(avp, struct diff_avp);
899  diff_init_avp(avp);
900  avp->name = bu_strdup(attr_name);
901  avp->state = DIFF_CONFLICT;
902  if (attr_val_ancestor) avp->ancestor_value = bu_strdup(attr_val_ancestor);
903  if (attr_val_right) avp->right_value = bu_strdup(attr_val_right);
904  if (attr_val_left) avp->left_value = bu_strdup(attr_val_left);
905  bu_ptbl_ins(diffs, (long *)avp);
906  return avp->state;
907 }
908 
909 HIDDEN int
910 diff3_dp_attr_unchgd(const char *attr_name, const char *attr_val, void *data)
911 {
912  struct bu_ptbl *diffs = (struct bu_ptbl *)data;
913  struct diff_avp *avp;
914  BU_GET(avp, struct diff_avp);
915  diff_init_avp(avp);
916  avp->state = DIFF_UNCHANGED;
917  avp->name = bu_strdup(attr_name);
918  avp->ancestor_value = bu_strdup(attr_val);
919  avp->right_value = bu_strdup(attr_val);
920  avp->left_value = bu_strdup(attr_val);
921  bu_ptbl_ins(diffs, (long *)avp);
922  return avp->state;
923 }
924 
925 int
926 db_diff3_dp(const struct db_i *left,
927  const struct db_i *ancestor,
928  const struct db_i *right,
929  const struct directory *left_dp,
930  const struct directory *ancestor_dp,
931  const struct directory *right_dp,
932  const struct bn_tol *diff3_tol,
933  db_compare_criteria_t flags,
934  struct diff_result *ext_result)
935 {
936  int state = DIFF_EMPTY;
937 
938  struct diff_elements left_components;
939  struct diff_elements ancestor_components;
940  struct diff_elements right_components;
941 
942  struct diff_result *result = NULL;
943 
944  if (left == DBI_NULL && ancestor == DBI_NULL && right == DBI_NULL) return -1;
945  if (left_dp == RT_DIR_NULL && ancestor_dp == RT_DIR_NULL && right_dp == RT_DIR_NULL) return -1;
946  if (!diff3_tol) return -1;
947 
948  /* If we aren't populating a result struct for the
949  * caller, use a local copy to keep the code simple */
950  if (!ext_result) {
951  BU_GET(result, struct diff_result);
952  diff_init_result(result, diff3_tol, "tmp");
953  } else {
954  result = ext_result;
955  }
956 
957  if (left_dp) result->dp_left = left_dp;
958  if (ancestor_dp) result->dp_ancestor = ancestor_dp;
959  if (right_dp) result->dp_right = right_dp;
960 
961  get_diff_components(&left_components, left, left_dp);
962  get_diff_components(&ancestor_components, ancestor, ancestor_dp);
963  get_diff_components(&right_components, right, right_dp);
964 
965  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_PARAM) {
966 
967  result->param_state |= db_avs_diff3(left_components.params, ancestor_components.params, right_components.params,
969  diff3_dp_attr_unchgd, (void *)(result->param_diffs));
970  /*compare the idb_ptr memory, if the types are the same.*/
971  if (left_components.bin_params && ancestor_components.bin_params && right_components.bin_params)
972  if (left_components.idb_ptr && ancestor_components.idb_ptr && right_components.idb_ptr) {
973  if ((left_components.intern->idb_minor_type == ancestor_components.intern->idb_minor_type) &&
974  (left_components.intern->idb_minor_type == right_components.intern->idb_minor_type)) {
975  int memsize = rt_intern_struct_size(left_components.intern->idb_minor_type);
976  if (memcmp((void *)left_components.idb_ptr, (void *)right_components.idb_ptr, memsize) &&
977  memcmp((void *)ancestor_components.idb_ptr, (void *)right_components.idb_ptr, memsize)) {
978  /* If we didn't pick up differences in the avs comparison, we need to use this result to flag a parameter difference */
979  if (result->param_state == DIFF_UNCHANGED || result->param_state == DIFF_EMPTY) result->param_state |= DIFF_CHANGED;
980  } else {
981  if (result->param_state == DIFF_EMPTY) result->param_state |= DIFF_UNCHANGED;
982  }
983  }
984  }
985  }
986 
987  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_ATTRS) {
988  result->param_state |= db_avs_diff3(left_components.attrs, ancestor_components.attrs, right_components.attrs,
990  diff3_dp_attr_unchgd, (void *)(result->attr_diffs));
991  }
992 
993  free_diff_components(&left_components);
994  free_diff_components(&ancestor_components);
995  free_diff_components(&right_components);
996 
997  state |= result->param_state;
998  state |= result->attr_state;
999 
1000  if (!ext_result) {
1001  diff_free_result(result);
1002  BU_PUT(result, struct diff_result);
1003  }
1004 
1005  return state;
1006 }
1007 
1008 int
1009 db_diff3(const struct db_i *dbip_left,
1010  const struct db_i *dbip_ancestor,
1011  const struct db_i *dbip_right,
1012  const struct bn_tol *diff3_tol,
1013  db_compare_criteria_t flags,
1014  struct bu_ptbl *results)
1015 {
1016  int state = DIFF_EMPTY;
1017  struct directory *dp_ancestor, *dp_left, *dp_right;
1018 
1019  /* Step 1: look at all objects in the ancestor database */
1020  FOR_ALL_DIRECTORY_START(dp_ancestor, dbip_ancestor) {
1021  struct bu_external ext_left, ext_ancestor, ext_right;
1022  struct diff_result *result;
1023  int ancestor_state = DIFF_EMPTY;
1024  int extern_state = DIFF_UNCHANGED;
1025  BU_GET(result, struct diff_result);
1026  diff_init_result(result, diff3_tol, dp_ancestor->d_namep);
1027 
1028  dp_left = db_lookup(dbip_left, dp_ancestor->d_namep, 0);
1029  dp_right = db_lookup(dbip_right, dp_ancestor->d_namep, 0);
1030 
1031  /* If we're checking everything, we want a sanity check to make sure we spot it when the objects differ */
1032  if (flags == DB_COMPARE_ALL &&
1033  dp_left != RT_DIR_NULL && dp_left->d_major_type != DB5_MAJORTYPE_ATTRIBUTE_ONLY &&
1034  dp_ancestor != RT_DIR_NULL && dp_ancestor->d_major_type != DB5_MAJORTYPE_ATTRIBUTE_ONLY &&
1035  dp_right != RT_DIR_NULL && dp_right->d_major_type != DB5_MAJORTYPE_ATTRIBUTE_ONLY) {
1036  if (db_get_external(&ext_left, dp_left, dbip_left) || db_get_external(&ext_ancestor, dp_ancestor, dbip_ancestor) || db_get_external(&ext_right, dp_right, dbip_right)) {
1037  bu_log("Warning - Error getting bu_external form when comparing %s and %s\n", dp_left->d_namep, dp_ancestor->d_namep);
1038  } else {
1039  if (db_diff_external(&ext_left, &ext_right) || db_diff_external(&ext_left, &ext_ancestor)) {extern_state = DIFF_CHANGED;}
1040  }
1041  bu_free_external(&ext_left);
1042  bu_free_external(&ext_ancestor);
1043  bu_free_external(&ext_right);
1044  }
1045 
1046  /* Do internal diffs */
1047  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_PARAM) {
1048  ancestor_state |= db_diff3_dp(dbip_left, dbip_ancestor, dbip_right, dp_left, dp_ancestor, dp_right, diff3_tol, DB_COMPARE_PARAM, result);
1049  }
1050  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_ATTRS) {
1051  ancestor_state |= db_diff3_dp(dbip_left, dbip_ancestor, dbip_right, dp_left, dp_ancestor, dp_right, diff3_tol, DB_COMPARE_ATTRS, result);
1052  }
1053  if (flags == DB_COMPARE_ALL && (ancestor_state == DIFF_UNCHANGED || ancestor_state == DIFF_EMPTY) && extern_state == DIFF_CHANGED) {
1054  bu_log("Warning - internal comparison and bu_external comparison disagree\n");
1055  }
1056 
1057  if (results) {
1058  bu_ptbl_ins(results, (long *)result);
1059  } else {
1060  diff_free_result(result);
1061  BU_PUT(result, struct diff_result);
1062  }
1063  state |= ancestor_state;
1064 
1066 
1067  FOR_ALL_DIRECTORY_START(dp_left, dbip_left) {
1068  dp_ancestor = db_lookup(dbip_ancestor, dp_left->d_namep, 0);
1069  if (dp_ancestor == RT_DIR_NULL) {
1070  struct bu_external ext_left, ext_right;
1071  int left_state = DIFF_EMPTY;
1072  int extern_state = DIFF_UNCHANGED;
1073  struct diff_result *result;
1074  BU_GET(result, struct diff_result);
1075  diff_init_result(result, diff3_tol, dp_left->d_namep);
1076 
1077  dp_right = db_lookup(dbip_right, dp_left->d_namep, 0);
1078 
1079  /* If we're checking everything, we want a sanity check to make sure we spot it when the objects differ */
1080  if (flags == DB_COMPARE_ALL &&
1081  dp_left != RT_DIR_NULL && dp_left->d_major_type != DB5_MAJORTYPE_ATTRIBUTE_ONLY &&
1082  dp_right != RT_DIR_NULL && dp_right->d_major_type != DB5_MAJORTYPE_ATTRIBUTE_ONLY) {
1083  if (db_get_external(&ext_left, dp_left, dbip_left) || db_get_external(&ext_right, dp_right, dbip_right)) {
1084  bu_log("Warning - Error getting bu_external form\n");
1085  } else {
1086  if (db_diff_external(&ext_left, &ext_right)) {extern_state = DIFF_CHANGED;}
1087  }
1088  bu_free_external(&ext_left);
1089  bu_free_external(&ext_right);
1090  }
1091 
1092  /* Do internal diffs */
1093  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_PARAM) {
1094  left_state |= db_diff3_dp(dbip_left, dbip_ancestor, dbip_right, dp_left, NULL, dp_right, diff3_tol, DB_COMPARE_PARAM, result);
1095  }
1096  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_ATTRS) {
1097  left_state |= db_diff3_dp(dbip_left, dbip_ancestor, dbip_right, dp_left, NULL, dp_right, diff3_tol, DB_COMPARE_ATTRS, result);
1098  }
1099  if (flags == DB_COMPARE_ALL && (left_state == DIFF_UNCHANGED || left_state == DIFF_EMPTY) && extern_state == DIFF_CHANGED) {
1100  bu_log("Warning - internal comparison and bu_external comparison disagree");
1101  }
1102 
1103  if (results) {
1104  bu_ptbl_ins(results, (long *)result);
1105  } else {
1106  diff_free_result(result);
1107  BU_PUT(result, struct diff_result);
1108  }
1109 
1110  state |= left_state;
1111  }
1112 
1114 
1115  FOR_ALL_DIRECTORY_START(dp_right, dbip_right) {
1116  dp_ancestor = db_lookup(dbip_ancestor, dp_right->d_namep, 0);
1117  dp_left = db_lookup(dbip_left, dp_right->d_namep, 0);
1118  if (dp_ancestor == RT_DIR_NULL && dp_left == RT_DIR_NULL) {
1119  struct diff_result *result;
1120  BU_GET(result, struct diff_result);
1121  diff_init_result(result, diff3_tol, dp_right->d_namep);
1122 
1123  /* Do internal diffs */
1124  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_PARAM) {
1125  state |= db_diff3_dp(dbip_left, dbip_ancestor, dbip_right, dp_left, dp_ancestor, dp_right, diff3_tol, DB_COMPARE_PARAM, result);
1126  }
1127  if (flags == DB_COMPARE_ALL || flags & DB_COMPARE_ATTRS) {
1128  state |= db_diff3_dp(dbip_left, dbip_ancestor, dbip_right, dp_left, dp_ancestor, dp_right, diff3_tol, DB_COMPARE_ATTRS, result);
1129  }
1130 
1131  if (results) {
1132  bu_ptbl_ins(results, (long *)result);
1133  } else {
1134  diff_free_result(result);
1135  BU_PUT(result, struct diff_result);
1136  }
1137  }
1139 
1140  return state;
1141 }
1142 
1143 /*
1144  * Local Variables:
1145  * mode: C
1146  * tab-width: 8
1147  * indent-tabs-mode: t
1148  * c-file-style: "stroustrup"
1149  * End:
1150  * ex: shiftwidth=4 tabstop=8
1151  */
int attr_state
Definition: db_diff.h:59
char * d_namep
pointer to name string
Definition: raytrace.h:859
#define BN_TOL_INIT(_p)
Definition: tol.h:87
Definition: raytrace.h:800
#define ID_ARS
ARS.
Definition: raytrace.h:463
#define FOR_ALL_DIRECTORY_START(_dp, _dbip)
Definition: raytrace.h:895
unsigned char d_major_type
object major type
Definition: raytrace.h:870
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
int rt_db_get_internal(struct rt_db_internal *ip, const struct directory *dp, const struct db_i *dbip, const mat_t mat, struct resource *resp)
Definition: dir.c:76
#define BU_AVS_MAGIC
Definition: magic.h:46
char * right_value
Definition: db_diff.h:48
int db_diff(const struct db_i *dbip1, const struct db_i *dbip2, const struct bn_tol *diff_tol, db_compare_criteria_t flags, struct bu_ptbl *results)
Definition: db_diff.c:640
struct bu_attribute_value_set * params
Definition: db_diff.c:416
#define ID_PIPE
Pipe (wire) solid.
Definition: raytrace.h:473
#define DIFF_CHANGED
Definition: db_diff.h:36
double dist
>= 0
Definition: tol.h:73
#define ID_ARB8
Generalized ARB. V + 7 vectors.
Definition: raytrace.h:462
#define DIFF_CONFLICT
Definition: db_diff.h:37
#define ID_SUBMODEL
Instanced submodel.
Definition: raytrace.h:486
#define VSET(a, b, c, d)
Definition: color.c:53
#define ID_GRIP
Pseudo Solid Grip.
Definition: raytrace.h:480
int bu_avs_add(struct bu_attribute_value_set *avp, const char *attribute, const char *value)
Definition: avs.c:78
#define ID_JOINT
Pseudo Solid/Region Joint.
Definition: raytrace.h:481
void bu_avs_merge(struct bu_attribute_value_set *dest, const struct bu_attribute_value_set *src)
Definition: avs.c:154
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
#define ID_BOT
Bag o' triangles.
Definition: raytrace.h:488
const unsigned char * db5_get_raw_internal_ptr(struct db5_raw_internal *rip, const unsigned char *ip)
Definition: db5_io.c:245
double dist_sq
dist * dist
Definition: tol.h:74
struct directory * db_lookup(const struct db_i *, const char *name, int noisy)
Definition: db_lookup.c:153
HIDDEN int diff3_dp_attr_conflict(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data)
Definition: db_diff.c:894
const struct directory * dp_right
Definition: db_diff.h:57
#define ID_PARTICLE
Particle system solid.
Definition: raytrace.h:474
char * left_value
Definition: db_diff.h:46
HIDDEN int diff3_dp_attr_add(const char *attr_name, const char *attr_val_left, const char *attr_val_right, void *data)
Definition: db_diff.c:845
#define BN_TOL_MAGIC
Definition: magic.h:74
#define ID_NULL
Unused.
Definition: raytrace.h:458
void bu_free_external(struct bu_external *ep)
#define ID_MAXIMUM
Maximum defined ID_xxx value.
Definition: raytrace.h:516
void * idb_ptr
Definition: db_diff.c:415
#define FOR_ALL_DIRECTORY_END
Definition: raytrace.h:899
#define ID_HF
Height Field.
Definition: raytrace.h:482
Header file for the BRL-CAD common definitions.
const char * value
Definition: avs.h:62
const struct directory * dp_ancestor
Definition: db_diff.h:56
#define ID_TOR
Toroid.
Definition: raytrace.h:459
#define ID_CLINE
FASTGEN4 CLINE solid.
Definition: raytrace.h:487
#define ID_BSPLINE
B-spline object.
Definition: raytrace.h:467
int bu_ptbl_ins(struct bu_ptbl *b, long *p)
#define ID_COMBINATION
Combination Record.
Definition: raytrace.h:499
int db_avs_diff(const struct bu_attribute_value_set *left_set, const struct bu_attribute_value_set *right_set, const struct bn_tol *diff_tol, int(*add_func)(const char *attr_name, const char *attr_val, void *data), int(*del_func)(const char *attr_name, const char *attr_val, void *data), int(*chgd_func)(const char *attr_name, const char *attr_val_left, const char *attr_val_right, void *data), int(*unchgd_func)(const char *attr_name, const char *attr_val, void *data), void *client_data)
Definition: db_diff.c:365
char ft_label[9]
Definition: raytrace.h:2044
HIDDEN int diff_dp_attr_unchgd(const char *attr_name, const char *attr_val, void *data)
Definition: db_diff.c:556
#define ID_BINUNIF
Uniform-array binary.
Definition: raytrace.h:501
#define HIDDEN
Definition: common.h:86
#define ID_VOL
3-D Volume
Definition: raytrace.h:471
char * ancestor_value
Definition: db_diff.h:47
int param_state
Definition: db_diff.h:58
Definition: ptbl.h:62
const char * bu_avs_get(const struct bu_attribute_value_set *avp, const char *attribute)
Definition: avs.c:172
#define ID_METABALL
Metaball.
Definition: raytrace.h:508
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
HIDDEN const char * arb_type_to_str(int type)
Definition: db_diff.c:218
COMPLEX data[64]
Definition: fftest.c:34
#define ID_DSP
Displacement map.
Definition: raytrace.h:483
#define ID_ANNOTATION
Annotation.
Definition: raytrace.h:513
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
#define DIFF_UNCHANGED
Definition: db_diff.h:33
#define ID_HYP
Hyperboloid of one sheet.
Definition: raytrace.h:510
#define ID_EHY
Elliptical Hyperboloid.
Definition: raytrace.h:478
#define ID_EBM
Extruded bitmap solid.
Definition: raytrace.h:470
void diff_init_result(struct diff_result *result, const struct bn_tol *curr_diff_tol, const char *obj_name)
Definition: db_diff.c:268
#define ID_CONSTRAINT
Constraint object.
Definition: raytrace.h:503
const struct directory * dp_left
Definition: db_diff.h:55
int db_get_external(struct bu_external *ep, const struct directory *dp, const struct db_i *dbip)
struct bu_ptbl * param_diffs
Definition: db_diff.h:60
int db_diff3_dp(const struct db_i *left, const struct db_i *ancestor, const struct db_i *right, const struct directory *left_dp, const struct directory *ancestor_dp, const struct directory *right_dp, const struct bn_tol *diff3_tol, db_compare_criteria_t flags, struct diff_result *ext_result)
Definition: db_diff.c:926
#define BU_PTBL_GET(ptbl, i)
Definition: ptbl.h:108
#define DIFF_EMPTY
Definition: db_diff.h:32
#define RT_DB_INTERNAL_INIT(_p)
Definition: raytrace.h:199
const struct rt_functab * idb_meth
for ft_ifree(), etc.
Definition: raytrace.h:194
#define ID_NMG
n-Manifold Geometry solid
Definition: raytrace.h:469
uint8_t * ext_buf
Definition: parse.h:216
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
#define BU_AVS_FOR(_pp, _avp)
Definition: avs.h:141
HIDDEN void get_diff_components(struct diff_elements *el, const struct db_i *dbip, const struct directory *dp)
Definition: db_diff.c:421
#define BU_AVS_IS_INITIALIZED(_ap)
Definition: avs.h:118
HIDDEN int diff_dp_attr_chgd(const char *attr_name, const char *attr_val_left, const char *attr_val_right, void *data)
Definition: db_diff.c:541
struct bu_attribute_value_set idb_avs
Definition: raytrace.h:196
HIDDEN int rt_intern_struct_size(int type)
Definition: db_diff.c:48
#define BN_TOL_DIST
Definition: tol.h:109
char * name
Definition: db_diff.h:44
#define BU_PTBL_INIT(_p)
Definition: ptbl.h:80
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
uint32_t magic
Definition: avs.h:84
int bin_params
Definition: db_diff.c:414
Support for uniform tolerances.
Definition: tol.h:71
#define ID_SPH
Sphere.
Definition: raytrace.h:468
#define ID_HALF
Half-space.
Definition: raytrace.h:464
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
int(* ft_get)(struct bu_vls *, const struct rt_db_internal *, const char *item)
Definition: raytrace.h:2180
int db_diff3(const struct db_i *dbip_left, const struct db_i *dbip_ancestor, const struct db_i *dbip_right, const struct bn_tol *diff3_tol, db_compare_criteria_t flags, struct bu_ptbl *results)
Definition: db_diff.c:1009
HIDDEN int diff3_dp_attr_del(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data)
Definition: db_diff.c:860
#define ID_BREP
B-rep object.
Definition: raytrace.h:509
#define ID_REC
Right Elliptical Cylinder [TGC special].
Definition: raytrace.h:465
#define BU_PTBL_LEN(ptbl)
Definition: ptbl.h:107
void bu_ptbl_free(struct bu_ptbl *b)
Definition: ptbl.c:226
#define ID_RHC
Right Hyperbolic Cylinder.
Definition: raytrace.h:476
#define ID_ARBN
ARB with N faces.
Definition: raytrace.h:472
int db5_import_attributes(struct bu_attribute_value_set *avs, const struct bu_external *ap)
Definition: attributes.c:30
HIDDEN int diff_dp_attr_del(const char *attr_name, const char *attr_val, void *data)
Definition: db_diff.c:527
#define ID_EPA
Elliptical Paraboloid.
Definition: raytrace.h:477
double perp
nearly 0
Definition: tol.h:75
void diff_free_result(struct diff_result *result)
Definition: db_diff.c:299
int db_diff_dp(const struct db_i *left, const struct db_i *right, const struct directory *left_dp, const struct directory *right_dp, const struct bn_tol *diff_tol, db_compare_criteria_t flags, struct diff_result *ext_result)
Definition: db_diff.c:571
HIDDEN int avpp_val_compare(const char *val1, const char *val2, const struct bn_tol *diff_tol)
Definition: db_diff.c:323
void * idb_ptr
Definition: raytrace.h:195
#define BU_AVS_INIT(_ap)
Definition: avs.h:102
char * obj_name
Definition: db_diff.h:53
int db_avs_diff3(const struct bu_attribute_value_set *left_set, const struct bu_attribute_value_set *ancestor_set, const struct bu_attribute_value_set *right_set, const struct bn_tol *diff_tol, int(*add_func)(const char *attr_name, const char *attr_val_left, const char *attr_val_right, void *data), int(*del_func)(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data), int(*chgd_func)(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data), int(*conflict_func)(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data), int(*unchgd_func)(const char *attr_name, const char *attr_val, void *data), void *client_data)
Definition: db_diff.c:726
#define DBI_NULL
Definition: raytrace.h:827
struct rt_db_internal * intern
Definition: db_diff.c:413
struct bu_ptbl * attr_diffs
Definition: db_diff.h:61
#define ID_PNTS
Collection of Points.
Definition: raytrace.h:512
#define ID_SUPERELL
Superquadratic ellipsoid.
Definition: raytrace.h:507
struct bn_tol * diff_tol
Definition: db_diff.h:54
#define ID_POLY
Polygonal faceted object.
Definition: raytrace.h:466
HIDDEN int diff_dp_attr_add(const char *attr_name, const char *attr_val, void *data)
Definition: db_diff.c:513
#define RT_DIR_NULL
Definition: raytrace.h:875
#define BU_EXTERNAL_INIT(_p)
Definition: parse.h:229
#define ID_REVOLVE
Solid of Revolution.
Definition: raytrace.h:511
db_compare_criteria_t
Definition: db_diff.h:72
int idb_minor_type
ID_xxx.
Definition: raytrace.h:193
HIDDEN const char * type_to_str(const struct rt_db_internal *obj, int arb_type)
Definition: db_diff.c:242
HIDDEN int db_diff_external(const struct bu_external *ext1, const struct bu_external *ext2)
Definition: db_diff.c:399
const char * name
Definition: avs.h:61
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
int rt_arb_std_type(const struct rt_db_internal *ip, const struct bn_tol *tol)
Definition: arb8.c:317
int tcl_list_to_avs(const char *tcl_list, struct bu_attribute_value_set *avs, int offset)
Definition: db_diff.c:187
#define ID_EXTRUDE
Solid of extrusion.
Definition: raytrace.h:485
HIDDEN void free_diff_components(struct diff_elements *el)
Definition: db_diff.c:500
HIDDEN int diff3_dp_attr_chgd(const char *attr_name, const char *attr_val_left, const char *attr_val_ancestor, const char *attr_val_right, void *data)
Definition: db_diff.c:878
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
#define ID_RPC
Right Parabolic Cylinder.
Definition: raytrace.h:475
size_t ext_nbytes
Definition: parse.h:210
#define ID_HRT
Heart.
Definition: raytrace.h:514
HIDDEN int diff3_dp_attr_unchgd(const char *attr_name, const char *attr_val, void *data)
Definition: db_diff.c:910
void diff_init_avp(struct diff_avp *attr_result)
Definition: db_diff.c:248
void diff_free_avp(struct diff_avp *attr_result)
Definition: db_diff.c:258
#define ID_TGC
Generalized Truncated General Cone.
Definition: raytrace.h:460
const char * name
Definition: db_diff.c:411
Definition: vls.h:56
#define BRLCAD_ERROR
Definition: defines.h:72
struct bu_attribute_value_set * attrs
Definition: db_diff.c:417
#define ID_ETO
Elliptical Torus.
Definition: raytrace.h:479
double fastf_t
Definition: defines.h:300
#define ID_ELL
Ellipsoid.
Definition: raytrace.h:461
#define ID_SKETCH
2D sketch
Definition: raytrace.h:484
void bu_avs_free(struct bu_attribute_value_set *avp)
Definition: avs.c:235
double para
nearly 1
Definition: tol.h:76
int state
Definition: db_diff.h:45
void rt_db_free_internal(struct rt_db_internal *ip)
Definition: dir.c:216
#define bu_strdup(s)
Definition: str.h:71
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126