BRL-CAD
push.c
Go to the documentation of this file.
1 /* P U S H . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2008-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library 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 library 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 libged/push.c
21  *
22  * The push command.
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <stdlib.h>
29 #include <string.h>
30 
31 
32 #include "bu/cmd.h"
33 #include "bu/getopt.h"
34 
35 #include "./ged_private.h"
36 
37 
38 #define PUSH_MAGIC_ID 0x50495323
39 #define FOR_ALL_PUSH_SOLIDS(_p, _phead) \
40  for (_p=_phead.forw; _p!=&_phead; _p=_p->forw)
41 
42 /** structure to hold all solids that have been pushed. */
43 struct push_id {
44  uint32_t magic;
45  struct push_id *forw, *back;
46  struct directory *pi_dir;
47  mat_t pi_mat;
48 };
49 
50 
51 struct push_data {
52  struct ged *gedp;
53  struct push_id pi_head;
55 };
56 
57 
58 static void
59 do_identitize(struct db_i *dbip, struct rt_comb_internal *UNUSED(comb), union tree *comb_leaf, void *user_ptr1, void *UNUSED(user_ptr2), void *UNUSED(user_ptr3), void *UNUSED(user_ptr4));
60 
61 
62 /**
63  * Traverses an objects paths, setting all member matrices == identity
64  */
65 static void
66 identitize(struct directory *dp,
67  struct db_i *dbip,
68  struct bu_vls *msg)
69 {
70  struct rt_db_internal intern;
71  struct rt_comb_internal *comb;
72 
73  if (dp->d_flags & RT_DIR_SOLID)
74  return;
75  if (rt_db_get_internal(&intern, dp, dbip, (fastf_t *)NULL, &rt_uniresource) < 0) {
76  bu_vls_printf(msg, "Database read error, aborting\n");
77  return;
78  }
79  comb = (struct rt_comb_internal *)intern.idb_ptr;
80  if (comb->tree) {
81  db_tree_funcleaf(dbip, comb, comb->tree, do_identitize,
82  (void *)msg, (void *)NULL, (void *)NULL, (void *)NULL);
83  if (rt_db_put_internal(dp, dbip, &intern, &rt_uniresource) < 0) {
84  bu_vls_printf(msg, "Cannot write modified combination (%s) to database\n", dp->d_namep);
85  return;
86  }
87  }
88 }
89 
90 
91 /**
92  * This routine must be prepared to run in parallel.
93  *
94  * @brief
95  * This routine is called once for eas leaf (solid) that is to
96  * be pushed. All it does is build at push_id linked list. The
97  * linked list could be handled by bu_list macros but it is simple
98  * enough to do hear with out them.
99  */
100 static union tree *
101 push_leaf(struct db_tree_state *tsp,
102  const struct db_full_path *pathp,
103  struct rt_db_internal *ip,
104  void *client_data)
105 {
106  union tree *curtree;
107  struct directory *dp;
108  struct push_id *gpip;
109  struct push_data *gpdp = (struct push_data *)client_data;
110 
111  RT_CK_TESS_TOL(tsp->ts_ttol);
112  BN_CK_TOL(tsp->ts_tol);
113  RT_CK_RESOURCE(tsp->ts_resp);
114 
115  dp = pathp->fp_names[pathp->fp_len-1];
116 
118  char *sofar = db_path_to_string(pathp);
119 
120  bu_vls_printf(gpdp->gedp->ged_result_str, "push_leaf(%s) path='%s'\n", ip->idb_meth->ft_name, sofar);
121  bu_free((void *)sofar, "path string");
122  }
123 /*
124  * XXX - This will work but is not the best method. dp->d_uses tells us
125  * if this solid (leaf) has been seen before. If it hasn't just add
126  * it to the list. If it has, search the list to see if the matrices
127  * match and do the "right" thing.
128  *
129  * (There is a question as to whether dp->d_uses is reset to zero
130  * for each tree walk. If it is not, then d_uses is NOT a safe
131  * way to check and this method will always work.)
132  */
134  FOR_ALL_PUSH_SOLIDS(gpip, gpdp->pi_head) {
135  if (gpip->pi_dir == dp) {
136  if (!bn_mat_is_equal(gpip->pi_mat,
137  tsp->ts_mat, tsp->ts_tol)) {
138  char *sofar = db_path_to_string(pathp);
139 
140  bu_vls_printf(gpdp->gedp->ged_result_str, "push_leaf: matrix mismatch between '%s' and prior reference.\n", sofar);
141  bu_free((void *)sofar, "path string");
142  gpdp->push_error = 1;
143  }
144 
146  RT_GET_TREE(curtree, tsp->ts_resp);
147  curtree->tr_op = OP_NOP;
148  return curtree;
149  }
150  }
151 /*
152  * This is the first time we have seen this solid.
153  */
154  BU_ALLOC(gpip, struct push_id);
155  gpip->magic = PUSH_MAGIC_ID;
156  gpip->pi_dir = dp;
157  MAT_COPY(gpip->pi_mat, tsp->ts_mat);
158  gpip->back = gpdp->pi_head.back;
159  gpdp->pi_head.back = gpip;
160  gpip->forw = &gpdp->pi_head;
161  gpip->back->forw = gpip;
163  RT_GET_TREE(curtree, tsp->ts_resp);
164  curtree->tr_op = OP_NOP;
165  return curtree;
166 }
167 
168 
169 /**
170  * @brief
171  * A null routine that does nothing.
172  */
173 static union tree *
174 push_region_end(struct db_tree_state *UNUSED(tsp), const struct db_full_path *UNUSED(pathp), union tree *curtree, void *UNUSED(client_data))
175 {
176  return curtree;
177 }
178 
179 
180 int
181 ged_push(struct ged *gedp, int argc, const char *argv[])
182 {
183  struct push_data *gpdp;
184  struct push_id *gpip;
185  struct rt_db_internal es_int;
186  int i;
187  int ncpu;
188  int c;
189  int old_debug;
190  int push_error;
191  static const char *usage = "object(s)";
192 
195  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
196 
197  /* initialize result */
198  bu_vls_trunc(gedp->ged_result_str, 0);
199 
200  /* must be wanting help */
201  if (argc == 1) {
202  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
203  return GED_HELP;
204  }
205 
206  BU_GET(gpdp, struct push_data);
207  gpdp->gedp = gedp;
208  gpdp->push_error = 0;
209  gpdp->pi_head.magic = PUSH_MAGIC_ID;
210  gpdp->pi_head.forw = gpdp->pi_head.back = &gpdp->pi_head;
211  gpdp->pi_head.pi_dir = (struct directory *) 0;
212 
213  old_debug = RT_G_DEBUG;
214 
215  /* Initial values for options, must be reset each time */
216  ncpu = 1;
217 
218  /* Parse options */
219  bu_optind = 1; /* re-init bu_getopt() */
220  while ((c=bu_getopt(argc, (char * const *)argv, "P:d")) != -1) {
221  switch (c) {
222  case 'P':
223  ncpu = atoi(bu_optarg);
224  if (ncpu<1) ncpu = 1;
225  break;
226  case 'd':
228  break;
229  case '?':
230  default:
231  bu_vls_printf(gedp->ged_result_str, "ged_push: usage push [-P processors] [-d] root [root2 ...]\n");
232  break;
233  }
234  }
235 
236  argc -= bu_optind;
237  argv += bu_optind;
238 
239  /*
240  * build a linked list of solids with the correct
241  * matrix to apply to each solid. This will also
242  * check to make sure that a solid is not pushed in two
243  * different directions at the same time.
244  */
245  i = db_walk_tree(gedp->ged_wdbp->dbip, argc, (const char **)argv,
246  ncpu,
248  0, /* take all regions */
249  push_region_end,
250  push_leaf, (void *)gpdp);
251 
252  /*
253  * If there was any error, then just free up the solid
254  * list we just built.
255  */
256  if (i < 0 || gpdp->push_error) {
257  while (gpdp->pi_head.forw != &gpdp->pi_head) {
258  gpip = gpdp->pi_head.forw;
259  gpip->forw->back = gpip->back;
260  gpip->back->forw = gpip->forw;
261  bu_free((void *)gpip, "Push ident");
262  }
263  RTG.debug = old_debug;
264  BU_PUT(gpdp, struct push_data);
265  bu_vls_printf(gedp->ged_result_str, "ged_push:\tdb_walk_tree failed or there was a solid moving\n\tin two or more directions");
266  return GED_ERROR;
267  }
268 /*
269  * We've built the push solid list, now all we need to do is apply
270  * the matrix we've stored for each solid.
271  */
272  FOR_ALL_PUSH_SOLIDS(gpip, gpdp->pi_head) {
273  if (rt_db_get_internal(&es_int, gpip->pi_dir, gedp->ged_wdbp->dbip, gpip->pi_mat, &rt_uniresource) < 0) {
274  bu_vls_printf(gedp->ged_result_str, "ged_push: Read error fetching '%s'\n", gpip->pi_dir->d_namep);
275  gpdp->push_error = -1;
276  continue;
277  }
278  RT_CK_DB_INTERNAL(&es_int);
279 
280  if (rt_db_put_internal(gpip->pi_dir, gedp->ged_wdbp->dbip, &es_int, &rt_uniresource) < 0) {
281  bu_vls_printf(gedp->ged_result_str, "ged_push(%s): solid export failure\n", gpip->pi_dir->d_namep);
282  }
283  rt_db_free_internal(&es_int);
284  }
285 
286  /*
287  * Now use the wdb_identitize() tree walker to turn all the
288  * matrices in a combination to the identity matrix.
289  * It would be nice to use db_tree_walker() but the tree
290  * walker does not give us all combinations, just regions.
291  * This would work if we just processed all matrices backwards
292  * from the leaf (solid) towards the root, but all in all it
293  * seems that this is a better method.
294  */
295 
296  while (argc > 0) {
297  struct directory *db;
298  db = db_lookup(gedp->ged_wdbp->dbip, *argv++, 0);
299  if (db)
300  identitize(db, gedp->ged_wdbp->dbip, gedp->ged_result_str);
301  --argc;
302  }
303 
304  /*
305  * Free up the solid table we built.
306  */
307  while (gpdp->pi_head.forw != &gpdp->pi_head) {
308  gpip = gpdp->pi_head.forw;
309  gpip->forw->back = gpip->back;
310  gpip->back->forw = gpip->forw;
311  bu_free((void *)gpip, "Push ident");
312  }
313 
314  RTG.debug = old_debug;
315  push_error = gpdp->push_error;
316  BU_PUT(gpdp, struct push_data);
317 
318  return push_error ? GED_ERROR : GED_OK;
319 }
320 
321 
322 static void
323 do_identitize(struct db_i *dbip, struct rt_comb_internal *UNUSED(comb), union tree *comb_leaf, void *user_ptr1, void *UNUSED(user_ptr2), void *UNUSED(user_ptr3), void *UNUSED(user_ptr4))
324 {
325  struct directory *dp;
326  struct bu_vls *msg = (struct bu_vls *)user_ptr1;
327 
328  RT_CK_DBI(dbip);
329  RT_CK_TREE(comb_leaf);
330 
331  if (!comb_leaf->tr_l.tl_mat) {
332  comb_leaf->tr_l.tl_mat = (matp_t)bu_malloc(sizeof(mat_t), "tl_mat");
333  }
334  MAT_IDN(comb_leaf->tr_l.tl_mat);
335  if ((dp = db_lookup(dbip, comb_leaf->tr_l.tl_name, LOOKUP_NOISY)) == RT_DIR_NULL)
336  return;
337 
338  identitize(dp, dbip, msg);
339 }
340 
341 
342 /*
343  * Local Variables:
344  * tab-width: 8
345  * mode: C
346  * indent-tabs-mode: t
347  * c-file-style: "stroustrup"
348  * End:
349  * ex: shiftwidth=4 tabstop=8
350  */
void usage(struct ged *gedp)
Definition: coil.c:315
#define GED_OK
Definition: ged.h:55
char * d_namep
pointer to name string
Definition: raytrace.h:859
Definition: raytrace.h:800
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
int rt_db_put_internal(struct directory *dp, struct db_i *dbip, struct rt_db_internal *ip, struct resource *resp)
Definition: dir.c:136
size_t fp_len
Definition: db_fullpath.h:44
#define OP_NOP
Leaf with no effect.
Definition: raytrace.h:1132
Definition: ged.h:338
uint32_t magic
Definition: push.c:44
struct db_i * dbip
Definition: raytrace.h:1266
void bu_semaphore_acquire(unsigned int i)
Definition: semaphore.c:180
#define FOR_ALL_PUSH_SOLIDS(_p, _phead)
Definition: push.c:39
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
#define GED_CHECK_ARGC_GT_0(_gedp, _argc, _flags)
Definition: ged.h:202
struct directory * db_lookup(const struct db_i *, const char *name, int noisy)
Definition: db_lookup.c:153
struct rt_wdb * ged_wdbp
Definition: ged.h:340
char * bu_optarg
Definition: globals.c:91
Header file for the BRL-CAD common definitions.
int bu_optind
Definition: globals.c:89
struct push_id * back
Definition: push.c:45
int bu_getopt(int nargc, char *const nargv[], const char *ostr)
Definition: getopt.c:43
#define GED_ERROR
Definition: ged.h:61
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
if(share_geom)
Definition: nmg_mod.c:3829
int bn_mat_is_equal(const mat_t a, const mat_t b, const struct bn_tol *tol)
Definition: mat.c:925
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
#define GED_CHECK_DATABASE_OPEN(_gedp, _flags)
Definition: ged.h:114
#define RT_G_DEBUG
Definition: raytrace.h:1718
struct ged * gedp
Definition: push.c:52
struct push_id * forw
Definition: push.c:45
#define RT_CK_DB_INTERNAL(_p)
Definition: raytrace.h:207
#define BU_ALLOC(_ptr, _type)
Definition: malloc.h:223
#define RT_DIR_SOLID
this name is a solid
Definition: raytrace.h:883
const struct rt_functab * idb_meth
for ft_ifree(), etc.
Definition: raytrace.h:194
Definition: push.c:51
#define RT_CK_TESS_TOL(_p)
Definition: raytrace.h:184
mat_t ts_mat
transform matrix
Definition: raytrace.h:1050
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
struct directory * pi_dir
Definition: push.c:46
mat_t pi_mat
Definition: push.c:47
matp_t tl_mat
xform matp, NULL ==> identity
Definition: raytrace.h:1173
char * tl_name
Name of this leaf (bu_strdup'ed)
Definition: raytrace.h:1174
char ft_name[17]
Definition: raytrace.h:2043
#define UNUSED(parameter)
Definition: common.h:239
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
#define BN_CK_TOL(_p)
Definition: tol.h:82
struct directory ** fp_names
array of dir pointers
Definition: db_fullpath.h:46
char * db_path_to_string(const struct db_full_path *pp)
Definition: db_fullpath.c:191
struct bu_vls * ged_result_str
Definition: ged.h:357
struct resource * ts_resp
Per-CPU data.
Definition: raytrace.h:1074
void bu_semaphore_release(unsigned int i)
Definition: semaphore.c:218
int push_error
Definition: push.c:54
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
#define RT_SEM_WORKER
Definition: raytrace.h:1730
struct push_id pi_head
Definition: push.c:53
struct tree::tree_db_leaf tr_l
#define RT_CK_RESOURCE(_p)
Definition: raytrace.h:1490
const struct rt_tess_tol * ts_ttol
Tessellation tolerance.
Definition: raytrace.h:1070
struct db_tree_state wdb_initial_tree_state
Definition: raytrace.h:1267
#define RT_GET_TREE(_tp, _res)
Definition: raytrace.h:1210
union tree * tree
Leading to tree_db_leaf leaves.
Definition: raytrace.h:938
int ged_push(struct ged *gedp, int argc, const char *argv[])
Definition: push.c:181
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
#define RT_DIR_NULL
Definition: raytrace.h:875
#define LOOKUP_NOISY
Definition: raytrace.h:892
#define GED_HELP
Definition: ged.h:62
uint32_t debug
!0 for debug, see librt/debug.h
Definition: raytrace.h:1695
void db_tree_funcleaf(struct db_i *dbip, struct rt_comb_internal *comb, union tree *comb_tree, void(*leaf_func)(struct db_i *, struct rt_comb_internal *, union tree *, void *, void *, void *, void *), void *user_ptr1, void *user_ptr2, void *user_ptr3, void *user_ptr4)
Definition: db_tree.c:640
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
#define RT_CK_TREE(_p)
Definition: raytrace.h:1182
int db_walk_tree(struct db_i *dbip, int argc, const char **argv, int ncpu, const struct db_tree_state *init_state, int(*reg_start_func)(struct db_tree_state *, const struct db_full_path *, const struct rt_comb_internal *, void *client_data), union tree *(*reg_end_func)(struct db_tree_state *, const struct db_full_path *, union tree *, void *client_data), union tree *(*leaf_func)(struct db_tree_state *, const struct db_full_path *, struct rt_db_internal *, void *client_data), void *client_data)
#define DEBUG_TREEWALK
22 Database tree traversal
Definition: raytrace.h:107
#define GED_CHECK_READ_ONLY(_gedp, _flags)
Definition: ged.h:181
int d_flags
flags
Definition: raytrace.h:869
Definition: vls.h:56
const struct bn_tol * ts_tol
Math tolerance.
Definition: raytrace.h:1071
double fastf_t
Definition: defines.h:300
void rt_db_free_internal(struct rt_db_internal *ip)
Definition: dir.c:216
#define PUSH_MAGIC_ID
Definition: push.c:38
Definition: push.c:43
struct rt_g RTG
Definition: globals.c:39