BRL-CAD
edit.c
Go to the documentation of this file.
1 /* E D I T . 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/edit.c
21  *
22  * Command to edit objects by translating, rotating, and scaling.
23  */
24 
25 #include "common.h"
26 
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <string.h>
30 
31 #include "bu/getopt.h"
32 #include "vmath.h"
33 #include "db.h"
34 #include "raytrace.h"
35 #include "ged.h"
36 #include "./ged_private.h"
37 
38 
39 /*
40  * rotate: Proposed operations, and manual page
41  *
42  * NAME
43  * rotate (alias for "edit rotate")
44  *
45  * SYNOPSIS
46  * rotate [-R] [AXIS] [CENTER] ANGLE OBJECT ...
47  * rotate [-R] [[AXIS_FROM] AXIS_TO] [CENTER] [ANGLE_ORIGIN]
48  * [ANGLE_FROM] ANGLE_TO OBJECT ...
49  * rotate [-R] [[[-n] -k {AXIS_FROM_OBJECT | AXIS_FROM_POS}]
50  * [[-n] [-a | -r] {AXIS_TO_OBJECT | AXIS_TO_POS}]]
51  * [[-n] -c {CENTER_OBJECT | CENTER_POS}]
52  * [[-n] -O {ANGLE_ORIGIN_OBJECT| ANGLE_ORIGIN_POS}]
53  * {[[-n] -k {ANGLE_FROM_OBJECT | ANGLE_FROM_POS}]
54  * [-n | -o] [-a | -r | -d] {ANGLE_TO_OBJECT | ANGLE_TO_POS}}
55  * OBJECT ...
56  *
57  * *OBJECT:
58  * [PATH/]OBJECT [OFFSET_DIST]
59  * [PATH/]OBJECT [x [y [z]]]
60  *
61  * *POS:
62  * {x [y [z]]} | {[-x {x | X_OBJECT}] [-y {y | Y_OBJECT}]
63  * [-z {z | Z_OBJECT}]}
64  *
65  * DESCRIPTION
66  * Used to rotate one or more instances of primitive or
67  * combination objects. OBJECTs rotate around CENTER at ANGLE,
68  * which is optionally constrained to rotating around AXIS. *POS
69  * represents either position, distance, degrees, or radians,
70  * depending on the context and supplied arguments.
71  *
72  * AXIS_FROM_POS is always interpreted as an absolute position.
73  * AXIS_TO_POS may be either an absolute position (-a), or a
74  * relative distance (-r) from AXIS_FROM. OFFSET_DIST is always a
75  * relative distance. A special case is made for ANGLE_TO_POS,
76  * which defaults to relative degrees from ANGLE_FROM_POS (-d),
77  * but may also be interpreted a as relative distance from
78  * ANGLE_FROM_POS (-r) or an absolute position (-a). See
79  * documentation of the -R option to see how it can be used to
80  * allow specification of radians. All *_TO_OBJECT arguments are
81  * always interpreted as absolute positions (-a).
82  *
83  * By default, AXIS is interpreted as the axis to rotate upon
84  * (but does not specify where), with the rotation angle
85  * ANGLE_TO_POS in relative degrees. The default AXIS is the
86  * x-axis, with AXIS_FROM at the origin and AXIS_TO at 1, 0, 0.
87  *
88  * Any *_OBJECT argument may be set to ".", which causes each
89  * individual OBJECT to be used in its place (a batch operation
90  * if there is more than one OBJECT).
91  *
92  * (see DESCRIPTION of translate command for other information)
93  *
94  * OPTIONS
95  *
96  * -R
97  * Interpret AXIS_TO as the center of a circle to rotate
98  * with, and the distance between AXIS_FROM and AXIS_TO as
99  * its radius. ANGLE_TO_POS is then interpreted as the amount
100  * to rotate OBJECT, in radians. If AXIS_TO is not provided,
101  * the center of the circle defaults to OBJECT. To use the
102  * natural origin of OBJECT as the center of the circle, use
103  * OBJECT as AXIS_TO_OBJECT, and enable option "-n".
104  *
105  * If -R is not given, the default is to interpret AXIS_FROM
106  * as the "zero" point of a new axis of rotation, and AXIS_TO
107  * as its endpoint, with ANGLE_TO_POS interpreted as relative
108  * number of degrees to rotate from ANGLE_FROM.
109  *
110  * -c CENTER_OBJECT | CENTER_POS
111  * Set CENTER of the rotation. If omitted, CENTER defaults to
112  * the bounding box center of the first OBJECT. To use the
113  * natural origin of the first OBJECT as CENTER, you must set
114  * CENTER_OBJECT to OBJECT and enable the matching -n option.
115  * Set CENTER_OBJECT to "." to to force each OBJECT to rotate
116  * around its own center.
117  *
118  * -O ANGLE_ORIGIN_OBJECT | ANGLE_ORIGIN_POS
119  * Sets ANGLE_ORIGIN, the origin of ANGLE. ANGLE_ORIGIN
120  * defaults to CENTER, the center of the rotation.
121  *
122  * -n *_FROM_OBJECT | *_TO_OBJECT
123  * Use the natural origin of *_FROM_OBJECT or *_TO_OBJECT,
124  * rather than the default of the bounding box center.
125  *
126  * -k *_FROM_POS | *_FROM_OBJECT
127  * Sets the keypoint for the angle or axis of rotation.
128  *
129  * If the AXIS_FROM keypoint is omitted, it defaults to the
130  * origin (0, 0, 0).
131  *
132  * The line between the points ANGLE_ORIGIN and ANGLE_FROM
133  * defines the y-axis of a custom AXIS. Therefore, if AXIS is
134  * omitted, ANGLE_FROM defaults to a point y-offset +1 from
135  * ANGLE_ORIGIN; the y-axis of the drawing. In essence,
136  * ANGLE_FROM helps define the y-axis, and AXIS defines the
137  * x-axis.
138  *
139  * If AXIS is provided, then ANGLE_FROM is aligned to it in
140  * such a way that the 90 degree angle created by the
141  * following points is maintained (as illustrated below):
142  *
143  * 1) ANGLE_FROM ->
144  * 2) AXIS_TO superimposed onto ANGLE_ORIGIN ->
145  * 3) AXIS_FROM the same relative distance from the
146  * superimposed AXIS_TO that it was from the actual AXIS_TO
147  *
148  * Default: | Default 90 degree angle:
149  * |
150  * +z ANGLE_ORIGIN | AXIS_TO->ANGLE_ORIGIN
151  * | / (from OBJECT) | \ 90
152  * AXIS_FROM | o | o/ ANGLE_FROM
153  * \| | ^ /
154  * AXIS_TO o o | o o _______
155  * \ / \ \ | \ |compass
156  * o \ ANGLE_FROM | AXIS_FROM | +z
157  * +x/ +y\ (ANGLE_ORIGIN | | |
158  * -y 1) | |+x/ \+y
159  *
160  * This is achieved in a consistent manner by starting
161  * ANGLE_FROM at the x/y of the superimposed AXIS_FROM, and
162  * the z coordinate of ANGLE_ORIGIN, and rotating it
163  * counterclockwise around the z-axis of ANGLE_ORIGIN. The
164  * first encountered 90 degree angle is used. The result is
165  * that the line between ANGLE_ORIGIN and ANGLE_FROM defines
166  * the y-axis of the rotation, from the origin to positive-y.
167  * The rotation y-axis (ANGLE_FROM) is always perpendicular
168  * to the z-axis of the coordinate system.
169  *
170  * If ANGLE_FROM is set, the default AXIS is ignored, and
171  * the rotation to ANGLE_TO is unconstrained. This means that
172  * OBJECT may rotate at CENTER using any ANGLE. There is one
173  * exception: unconstrained rotations of exactly 180 degrees
174  * are ambiguous, and will therefore fail. To bypass this
175  * limitation, perform a relative rotation of 180 degrees in
176  * the direction required.
177  *
178  * If both ANGLE_FROM and AXIS are set, the rotation from
179  * ANGLE_FROM to ANGLE_TO is constrained around AXIS.
180  * This allows for the use of reference objects that are not
181  * perfectly lined up on AXIS.
182  *
183  * -o ANGLE_TO_POS
184  * Overrides constraint to AXIS. Only allowed when AXIS is
185  * supplied, and ANGLE_TO_POS is given in degrees or radians.
186  * Use -O when the axis you would like to rotate on is
187  * difficult to reference, but you are able to set AXIS to an
188  * axis that is perpendicular to it. ANGLE_TO_POS options -y
189  * or -z would then enable rotation upon the desired axis.
190  *
191  * -a *_TO_POS | *_TO_OBJECT
192  * Interpret *_TO_POS or *_TO_OBJECT as an absolute position.
193  * This option is required if *_TO_OBJECT is supplied.
194  *
195  * If any arguments precede AXIS_TO or ANGLE_TO, they are
196  * required to have a matching "-a", "-r", or, in the case of
197  * ANGLE_TO, "-d".
198  *
199  * -r *_TO_POS
200  * Interpret *_TO_POS as a point a relative distance from
201  * its *_FROM_POS keypoint. This is the default if *_TO_POS
202  * is set but *_FROM_POS is omitted. Must be omitted if
203  * *_TO_OBJECT is specified.
204  *
205  * If any arguments precede AXIS_TO or ANGLE_TO, they are
206  * required to have a matching "-a", "-r", or, in the case of
207  * ANGLE_TO, "-d".
208  *
209  * -d ANGLE_TO_POS
210  * Interpret ANGLE_TO_POS as relative degrees (or radians if
211  * -R is also set) to rotate its ANGLE_FROM_POS keypoint.
212  * This option implies -o (override AXIS), since constraining
213  * to AXIS is not helpful in this case. This option (-d) is
214  * the default, but in some cases it is required:
215  *
216  * If any arguments precede ANGLE_TO, it is required to have
217  * matching "-a", "-r", or "-d".
218  *
219  * EXAMPLES
220  *
221  * The following examples assume we are facing the top of a
222  * cube, which is centered at the origin, and intersects the x
223  * and y axes perpendicularly. Two spheres will serve to
224  * illustrate how reference objects may be used to aid in complex
225  * rotations. The angle between the spheres is intended to
226  * exactly represent the angle between the points at the corners
227  * of the cube that are facing us in the 2nd and 4th quadrants.
228  *
229  * +y cube sphere1
230  * ___|___ / /
231  * |q2 | q1| o
232  * -x __|___|___|___________+x
233  * |q3 | q4| o
234  * |___|___| /
235  * | sphere2
236  * -y
237  *
238  * # Rotate the cube 45 degrees counterclockwise around its
239  * # bounding box center, on the z-axis. The corner in q1 will
240  * # end up on the positive y-axis, intersecting the y/z plane.
241  * rotate -z 45 cube
242  *
243  * # all of these have the same result as above
244  * rotate 0 0 45 cube
245  * rotate -c 0 0 0 -d 0 0 45 cube
246  * rotate -c cube 0 0 45 cube
247  * rotate -c . 0 0 45 cube
248  * rotate -c -x . -y . -z . cube -z 45 cube
249  * rotate -c . -z 17 cube -z 45 cube -z -17
250  *
251  * # return it to the last position (clockwise)
252  * rotate -z -45 cube
253  *
254  * # return it to its last position (counterclockwise)
255  * rotate -z 315 cube
256  *
257  * # Rotate the cube (in 3d) so that the edge facing us in the
258  * # positive y quadrants is rolled directly down and towards us,
259  * # stopping where the edge in the negative y quadrants is now.
260  * rotate 90 cube.s
261  *
262  * # Rotate the cube in such a way that the corner facing us in
263  * # the q3 is pointing directly at us (we are on a positive z)
264  * rotate -45 45 cube
265  *
266  * # Rotate the cube on its center, from sphere1 to sphere2
267  * # (this just happens to be on the z-axis)
268  * rotate -k sphere1 -a sphere2 cube
269  *
270  * # all of these have the same result as above
271  * rotate -c cube -k sphere1 -a sphere2 cube
272  * rotate -c . -k sphere1 -a sphere2 cube
273  * rotate -k -z 0 -r -z 1 -k sphere1 -a sphere2 cube
274  * rotate -k -z 0 -a -z 1 -k sphere1 -a sphere2 cube
275  * rotate -k -z 0 -r -z 1 -c . -k sphere1 -a sphere2 cube
276  *
277  * # all of these rotate it back
278  * rotate -k -z 1 -r -z -1 -k sphere1 -a sphere2 cube
279  * rotate -k -z 1 -a -z 0 -k sphere1 -a sphere2 cube
280  * rotate -k -z 5000 -a -z 23 -k sphere1 -a sphere2 cube
281  *
282  * # Note that in the examples where AXIS is specified, even
283  * # if sphere1 and sphere2 had different z-coordinates for
284  * # their centers, the rotate behavior would be the same as
285  * # above. In the examples where AXIS is not specified,
286  * # however, the cube would rotate unconstrained in the
287  * # z-axis as well.
288  *
289  * # Rotate the cube around a point 25 units in front of itself
290  * # (the front is the right face in the diagram, sharing edge q1
291  * # and q4 with our top view) so that it faces the opposite
292  * # direction
293  * rotate -c . -x 25 -d 180 cube
294  *
295  * # same effect (preferred method)
296  * rotate -a 180 cube -x 25
297  *
298  * # Rotate the cube so that face that is facing us, is instead
299  * # facing sphere1 (a 3d rotation). Note that CENTER is using
300  * # its default of OBJECT's bounding box center, and
301  * # ANGLE_CENTER is using its default of CENTER.
302  * rotate -k . -z 1 -a sphere1 cube
303  *
304  * # all of these have the same result as above
305  * rotate -k . -z 5981 -a sphere1 cube
306  * rotate -k . -z .01 -a sphere1 cube
307  *
308  * # move it back
309  * rotate -k sphere1 -a . -z 1 cube
310  *
311  * # Rotate cube around an AXIS from sphere2 to sphere1
312  * rotate -k sphere2 -a sphere1 -c sphere2 -d 180 cube
313  *
314  * # same effect as above
315  * rotate -k sphere2 -a sphere1 -c sphere2 -d 180 cube
316  * rotate -k sphere1 -a sphere1 -c sphere1 -d 180 cube
317  *
318  * # rotate cube on the same axis, so that it is in front of
319  * # the spheres
320  * rotate -k sphere2 -a wphere1 -c sphere1 -d 90 cube
321  *
322  * # Rotate both spheres individually around separate axis,
323  * # so that the same points on each sphere are still facing
324  * # cube, but they are upside down.
325  * rotate -k . -a cube -c . -d 180 sphere1 sphere2
326  *
327  * # Rotate both spheres around an axis in the middle of them,
328  * # so that they switch places. Any point on AXIS points could
329  * # have been used as CENTER. If the spheres were at different
330  * # z-coordinates, this would still work.
331  * rotate -k sphere1 -y sphere2 -a sphere2 -y sphere1 -c sphere2
332  * -y sphere1 -d 180 sphere1 sphere2
333  *
334  *
335  */
336 
337 /*
338  * scale: Proposed operations, and manual page
339  *
340  * NAME
341  * scale (alias for "edit scale")
342  *
343  * SYNOPSIS
344  * scale [SCALE] [CENTER] FACTOR OBJECT ...
345  * scale [[SCALE_FROM] SCALE_TO] [CENTER] [FACTOR_FROM]
346  * FACTOR_TO OBJECT ...
347  * scale [[[-n] -k {SCALE_FROM_OBJECT | SCALE_FROM_POS}]
348  * [-n] [-a | -r] {SCALE_TO_OBJECT | SCALE_TO_POS}]
349  * [[-n] -c {CENTER_OBJECT | CENTER_POS}]
350  * [[-n] -k {FACTOR_FROM_OBJECT | FACTOR_FROM_POS}]
351  * [-n] [-a | -r] {FACTOR_TO_OBJECT | FACTOR_TO_POS} OBJECT
352  * ...
353  *
354  * *OBJECT:
355  * [PATH/]OBJECT [OFFSET_DIST]
356  * [PATH/]OBJECT [x [y [z]]]
357  *
358  * FACTOR_TO_POS:
359  * {xyz_factor | {x y [z]}} | {[-x {x | X_OBJ}]
360  * [-y {y | Y_OBJ}] [-z {z | Z_OBJ}]}
361  *
362  * *POS (except FACTOR_TO_POS):
363  * {x [y [z]]} | {[-x {x | X_OBJ}] [-y {y | Y_OBJ}]
364  * [-z {z | Z_OBJ}]}
365  *
366  * DESCRIPTION
367  * Used to enlarge or reduce the size of one or more instances of
368  * primitive or combination objects, by applying a scaling
369  * factor. OBJECTs are scaled by a FACTOR of SCALE, at CENTER.
370  *
371  * It is important to note that FACTOR is interpreted as a factor
372  * of SCALE. Although it might appear so, the distance between
373  * SCALE and FACTOR points is irrelevant.
374  *
375  * By default, the reference scale SCALE, is from a
376  * SCALE_FROM_POS of (0, 0, 0) to a SCALE_TO_POS of (1, 1, 1). Given
377  * these default SCALE values, specifying a FACTOR_TO_POS of
378  * (2, 2, 2) would double the size of OBJECT, while (0.5, 0.5, 0.5)
379  * would halve its size.
380  *
381  * If SCALE were from a SCALE_FROM_POS of (0, 0, 0) to a
382  * SCALE_TO_POS of (5, 10, 15), doubling the size of OBJECT would
383  * require a FACTOR_TO_POS of (10, 20, 30), or of (2.5, 5, 7.5) in
384  * order to halve it. Specifying a FACTOR_TO_POS of (30, 30, 30)
385  * would result in the x-axes of all OBJECT's being stretched to
386  * quintuple their original lengths, y-axes tripled in length,
387  * and z-axes double in length.
388  *
389  * (see DESCRIPTION of translate command for other information)
390  *
391  * OPTIONS
392  * -n *_FROM_OBJECT | *_TO_OBJECT
393  * Use the natural origin of *_FROM_OBJECT and/or
394  * *_TO_OBJECT, rather than the default of its bounding box
395  * center.
396  *
397  * -k *_FROM_OBJECT | *_FROM_POS
398  * Sets the keypoint to *_FROM_OBJECT's bounding box center
399  * (or natural origin if -n is used). If this option is
400  * omitted, the keypoint defaults to the first OBJECT's
401  * bounding box center.
402  *
403  * -c CENTER_OBJECT | CENTER_POS
404  * Set CENTER of where the scale will occur. If omitted,
405  * CENTER defaults to the bounding box center of the first
406  * OBJECT. To use the natural origin of the first OBJECT as
407  * CENTER, you must set CENTER_OBJECT to OBJECT and enable
408  * the matching -n option. Set CENTER_OBJECT to "." to to
409  * force each OBJECT to scale from its own center.
410  *
411  * -r *_TO_POS
412  * Interpret *_TO_POS as the relative distance to scale
413  * OBJECTs from FROM keypoint. This is the default if TO_POS
414  * is set. Must be omitted to specify *_TO_OBJECT is
415  * specified.
416  *
417  * -a *_TO_POS | *_TO_OBJECT
418  * Interpret TO_POS/TO_OBJECT as an absolute position. The
419  * vector implied by FROM and TO is used to scale OBJECT.
420  * This option is required if TO_OBJECT is specified.
421  *
422  * EXAMPLES
423  * # All of the following double the size of cube from its center
424  * scale 2 cube
425  * scale 2 2 2 cube
426  * scale -r 2 2 2 cube
427  * scale -r 2 cube
428  * scale -k 0 0 0 -a 2 2 2 cube
429  * scale -k 0 0 0 -a 1 1 1 -c cube -r 2 cube
430  * scale -k 0 0 0 -a 1 1 1 -c . -r 2 cube
431  * scale -k 0 0 0 -a 1 1 1 -c . -a 2 2 2 cube
432  * scale -k 5 10 15 -a 7 11 -2 -r 4 2 34 cube
433  * scale -k 5 10 15 -a 7 11 -2 -k 0 0 0 -a 4 2 34 cube
434  * scale -k 5 10 15 -a 7 11 -2 -k 0 0 0 -r 4 2 34 cube
435  * scale -k 5 10 15 -a 7 11 -2 -k 3 6 9 -r 7 8 43 cube
436  * scale -k 5 10 15 -a 7 11 -2 -c cube -k 3 6 9 -r 7 8 43 cube
437  *
438  */
439 
440 /* Max # of global options + max number of options for a single arg */
441 #define EDIT_MAX_ARG_OPTIONS 3
442 
443 /*
444  * Use one of these nodes for each argument of the edit subcommands
445  * (see manuals)
446  */
447 struct edit_arg {
448  struct edit_arg *next; /* nodes rel to arg in cmd args grouping */
449  char cl_options[EDIT_MAX_ARG_OPTIONS]; /* unique cmd line opts */
450  unsigned int coords_used : 7; /* flag which coords will be used */
451  unsigned int type : 7; /* flag the arg type and type modifiers */
452  struct db_full_path *object; /* path and obj */
453  vect_t *vector; /* abs pos, or offset dist from an obj */
454 };
455 
456 
457 /*
458  * edit_arg coordinate flags (careful: used in bitshift)
459  */
460 
461 /* edit_arg flags of coordinates that will be used */
462 #define EDIT_COORD_X 0x01
463 #define EDIT_COORD_Y 0x02
464 #define EDIT_COORD_Z 0x04
465 #define EDIT_COORDS_ALL (EDIT_COORD_X | EDIT_COORD_Y | EDIT_COORD_Z)
466 
467 /* edit_arg flags of coordinates that are already set; only used by
468  * edit_str[s]_to_arg(). Ignored by edit() */
469 /* FIXME: these shouldn't be edit_arg flags... edit_strs_to_arg()
470  * should just pass edit_str_to_arg() references to automatic vars */
471 #define EDIT_COORD_IS_SET_X 0x08
472 #define EDIT_COORD_IS_SET_Y 0x10
473 #define EDIT_COORD_IS_SET_Z 0x20
474 
475 /*
476  * edit_arg argument type flags
477  */
478 
479 /* argument types */
480 #define EDIT_FROM 0x01 /* aka keypoint */
481 #define EDIT_TO 0x02
482 #define EDIT_TARGET_OBJ 0x04 /* obj to operate on */
483 
484 /* "TO" argument type modifiers */
485 #define EDIT_REL_DIST 0x08
486 #define EDIT_ABS_POS 0x10
487 
488 /* object argument type modifiers */
489 #define EDIT_NATURAL_ORIGIN 0x20 /* use n.o. of object */
490 #define EDIT_USE_TARGETS 0x40 /* for batch ops */
491 
492 /* all type modifiers that indicate the arg contains an obj */
493 #define EDIT_OBJ_TYPE_MODS (EDIT_NATURAL_ORIGIN | EDIT_USE_TARGETS)
494 
495 /* in batch ops, these flags are not discarded from the target obj */
496 #define EDIT_TARGET_OBJ_BATCH_TYPES (EDIT_NATURAL_ORIGIN)
497 
498 
499 /*
500  * Arg groupings for each command.
501  */
502 union edit_cmd{
503  const struct edit_cmd_tab *cmd;
504 
505  struct {
507  struct edit_arg *objects;
508  } common;
509 
510  struct {
511  const struct edit_cmd_tab *padding_for_cmd;
512  struct edit_arg *args;
513  } cmd_line; /* similar to common; used when parsing cl args */
514 
515  struct {
516  const struct edit_cmd_tab *padding_for_cmd;
517  struct edit_arg *objects;
518  struct {
519  struct edit_arg *from;
520  struct edit_arg *to;
521  } ref_axis;
522  struct edit_arg *center;
523  struct {
524  struct edit_arg *origin;
525  struct edit_arg *from;
526  struct edit_arg *to;
527  } ref_angle;
528  } rotate;
529 
530  struct {
531  const struct edit_cmd_tab *padding_for_cmd;
532  struct edit_arg *objects;
533  struct {
534  struct edit_arg *from;
535  struct edit_arg *to;
536  } ref_scale;
537  struct edit_arg *center;
538  struct {
539  struct edit_arg *from;
540  struct edit_arg *to;
541  } ref_factor;
542  } scale;
543 
544  struct {
545  const struct edit_cmd_tab *padding_for_cmd;
546  struct edit_arg *objects;
547  struct {
548  struct edit_arg *from;
549  struct edit_arg *to;
550  } ref_vector;
551  } translate;
552 };
553 
554 
555 /**
556  * Command specific information, for a table of available commands.
557  */
558 typedef int (*exec_handler)(struct ged *gedp, const union edit_cmd *const cmd);
559 typedef int (*add_cl_args_handler)(struct ged *gedp, union edit_cmd *const cmd,
560  const int flags);
561 typedef struct edit_arg ** (*get_arg_head_handler)(
562  const union edit_cmd *const cmd, int idx);
563 
564 struct edit_cmd_tab {
565  char *name;
566  char *opt_global;
567  char *usage;
568  char *help;
569  int enabled;
570 #define EDIT_CMD_DISABLE 0x0
571 #define EDIT_CMD_ENABLE 0x1
575 };
576 
577 
578 /*
579  * Argument builder/helper functions
580  */
581 
582 
583 /**
584  * Initialize an argument node.
585  */
586 HIDDEN void
588 {
589  arg->next = (struct edit_arg *)NULL;
590  (void)memset((void *)&arg->cl_options[0], 0, EDIT_MAX_ARG_OPTIONS);
592  arg->type = 0;
593  arg->object = (struct db_full_path *)NULL;
594  arg->vector = (vect_t *)NULL;
595 }
596 
597 
598 /**
599  * Attach an argument node to the end of the list.
600  */
601 HIDDEN void
603  struct edit_arg *node)
604 {
605  struct edit_arg *pos = head;
606 
607  while (pos->next)
608  pos = pos->next;
609  pos->next = node;
610 }
611 
612 
613 /**
614  * Allocate space and attach a new node to the end of the list.
615  * Returns a pointer to the new node. Caller is responsible for
616  * freeing.
617  */
618 HIDDEN struct edit_arg *
620 {
621  struct edit_arg *arg;
622 
623  BU_ALLOC(arg, struct edit_arg);
624  edit_arg_postfix(head, arg);
625  edit_arg_init(arg);
626  return arg;
627 }
628 
629 
630 /**
631  * Duplicate an argument node on top of an existing node. Prior to
632  * calling, caller is responsible for freeing objects contained by
633  * destination argument node, if necessary, via edit_arg_free_inner().
634  */
635 HIDDEN void
637  const struct edit_arg *src)
638 {
639  int i;
640 
641  edit_arg_init(dest);
642  dest->next = (struct edit_arg *)NULL;
643  for (i = 0; i < EDIT_MAX_ARG_OPTIONS; ++i)
644  dest->cl_options[i] = src->cl_options[i];
645  dest->coords_used = src->coords_used;
646  dest->type = src->type;
647  if (src->object) {
648  BU_ALLOC(dest->object, struct db_full_path);
649  db_full_path_init(dest->object);
650  db_dup_full_path(dest->object, src->object);
651  }
652  if (src->vector) {
653  BU_ALLOC(dest->vector, vect_t);
654  (*dest->vector)[0] = (*src->vector)[0];
655  (*dest->vector)[1] = (*src->vector)[1];
656  (*dest->vector)[2] = (*src->vector)[2];
657  }
658 }
659 
660 
661 /**
662  * Duplicate an argument node into a new argument. Caller is
663  * responsible for freeing destination argument, using the
664  * appropriate edit_arg_free*() function.
665  */
666 HIDDEN void
667 edit_arg_duplicate(struct edit_arg **dest, const struct edit_arg *src)
668 {
669  BU_ALLOC(*dest, struct edit_arg);
670  edit_arg_duplicate_in_place(*dest, src);
671 }
672 
673 
674 /**
675  * Returns GED_OK if arg is empty, otherwise GED_ERROR is returned
676  */
677 HIDDEN int
679 {
680  if (!arg->next &&
681  (arg->cl_options[0] == '\0') &&
682  (arg->coords_used & EDIT_COORDS_ALL) &&
683  (!arg->type) &&
684  (!arg->object) &&
685  (!arg->vector))
686  return GED_OK;
687  return GED_ERROR;
688 }
689 
690 
691 /**
692  * Free all objects contained by an argument node.
693  */
694 HIDDEN void
696 {
697  if (arg->object) {
699  bu_free((void *)arg->object, "db_string_to_path");
700  arg->object = (struct db_full_path*)NULL;
701  }
702  if (arg->vector) {
703  bu_free(arg->vector, "vect_t");
704  arg->vector = (vect_t *)NULL;
705  }
706 }
707 
708 
709 /**
710  * Free an argument node, including what it contains.
711  */
712 HIDDEN void
714 {
715  edit_arg_free_inner(arg);
716  bu_free(arg, "edit_arg");
717 }
718 
719 
720 /**
721  * Free the last argument node in the list.
722  */
723 HIDDEN void
725 {
726  struct edit_arg *last_arg = arg;
727 
728  do {
729  if (!(arg->next))
730  break;
731  last_arg = arg;
732  } while ((arg = arg->next));
733  last_arg->next = (struct edit_arg *)NULL;
734  edit_arg_free(arg);
735 }
736 
737 
738 /**
739  * Free an argument node and all nodes down its list.
740  */
741 HIDDEN void
743 {
744  if (arg->next)
745  edit_arg_free_all(arg->next);
746  edit_arg_free(arg);
747 }
748 
749 
750 /**
751  * Gets the apparent coordinates of an object.
752  *
753  * Combines the effects of all the transformation matrices in the
754  * combinations in the given path that affect the position of the
755  * combination or shape at the end of the path. The result is the
756  * apparent coordinates of the object at the end of the path, if the
757  * first combination in the path were drawn. The only flags respected
758  * are object argument type modifier flags.
759  *
760  * If the path only contains a primitive, the coordinates of the
761  * primitive will be the result of the conversion.
762  *
763  * Returns GED_ERROR on failure, and GED_OK on success.
764  */
765 HIDDEN int
766 edit_arg_to_apparent_coord(struct ged *gedp, const struct edit_arg *const arg,
767  vect_t *const coord)
768 {
769  const struct db_full_path *const path = arg->object;
770  struct rt_db_internal intern;
771  struct directory *d;
772  struct directory *d_next;
773  struct rt_comb_internal *comb_i;
774  union tree *leaf;
775  vect_t leaf_deltas = VINIT_ZERO;
776  struct _ged_trace_data gtd;
777  point_t rpp_min;
778  point_t rpp_max;
779  size_t i;
780 
781  if (ged_path_validate(gedp, path) == GED_ERROR) {
782  bu_vls_printf(gedp->ged_result_str, "path \"%s\" does not exist in"
783  "the database", db_path_to_string(path));
784  return GED_ERROR;
785  }
786 
787  /* sum the transformation matrices of each object in path */
788  d = DB_FULL_PATH_ROOT_DIR(path);
789  for (i = (size_t)0; i < path->fp_len - (size_t)1; ++i) {
790  d_next = DB_FULL_PATH_GET(path, i + (size_t)1);
791 
792  /* The path was validated, and this loop doesn't process the
793  * last item, so it must be a combination.
794  */
796 
797  /* sum transformation matrices */
798  GED_DB_GET_INTERNAL(gedp, &intern, d, (fastf_t *)NULL,
800  comb_i = (struct rt_comb_internal *)intern.idb_ptr;
801  leaf = db_find_named_leaf(comb_i->tree, d_next->d_namep);
802  BU_ASSERT_PTR(leaf, !=, TREE_NULL); /* path is validated */
803  if (leaf->tr_l.tl_mat) {
804  MAT_DELTAS_GET(leaf_deltas, leaf->tr_l.tl_mat);
805  VADD2(*coord, *coord, leaf_deltas);
806  }
807 
808  rt_db_free_internal(&intern);
809  d = d_next; /* prime for next iteration */
810  }
811  d_next = RT_DIR_NULL; /* none left */
812 
813  /* add final combination/primitive natural origin to sum */
814  if (d->d_flags & RT_DIR_SOLID) {
815  if (_ged_get_obj_bounds2(gedp, 1, (const char **)&d->d_namep, &gtd,
816  rpp_min, rpp_max) == GED_ERROR)
817  return GED_ERROR;
818  } else {
820  if (ged_get_obj_bounds(gedp, 1, (const char **)&d->d_namep, 1,
821  rpp_min, rpp_max) == GED_ERROR)
822  return GED_ERROR;
823  }
824 
825  if (arg->type & EDIT_NATURAL_ORIGIN) {
826  if (d->d_flags & (RT_DIR_COMB | RT_DIR_REGION)) {
827  bu_vls_printf(gedp->ged_result_str, "combinations do not have a"
828  " natural origin (%s)", d->d_namep);
829  return GED_ERROR;
830  }
831 
832  GED_DB_GET_INTERNAL(gedp, &intern, d, (fastf_t *)NULL,
834  if (_ged_get_solid_keypoint(gedp, leaf_deltas, &intern, (const fastf_t *)gtd.gtd_xform) == GED_ERROR) {
835  bu_vls_printf(gedp->ged_result_str, "\nunable to get natural origin"
836  " of \"%s\"", d->d_namep);
837  return GED_ERROR;
838  }
839  rt_db_free_internal(&intern);
840  } else {
841  /* bounding box center is the default */
842  VADD2SCALE(leaf_deltas, rpp_min, rpp_max, 0.5);
843  }
844 
845  VADD2(*coord, *coord, leaf_deltas);
846  return GED_OK;
847 }
848 
849 
850 /**
851  * Converts an edit_arg object+offset to coordinates. If *coord is
852  * NULL, *arg->vector is overwritten with the coordinates and
853  * *arg->object is freed, otherwise coordinates are written to *coord
854  * and *arg is in no way modified.
855  *
856  * The only flags respected are object argument type modifier flags.
857  *
858  * Returns GED_ERROR on failure, and GED_OK on success.
859  */
860 HIDDEN int
861 edit_arg_to_coord(struct ged *gedp, struct edit_arg *const arg, vect_t *coord)
862 {
863  vect_t obj_coord = VINIT_ZERO;
864  vect_t **dest;
865 
866  if (coord)
867  dest = &coord;
868  else
869  dest = &arg->vector;
870 
871  if (edit_arg_to_apparent_coord(gedp, arg, &obj_coord) == GED_ERROR)
872  return GED_ERROR;
873 
874  if (arg->vector) {
875  VADD2(**dest, *arg->vector, obj_coord);
876  } else {
877  BU_ALLOC(*dest, vect_t);
878  VMOVE(**dest, obj_coord);
879  }
880 
881  if (!coord) {
883  bu_free((void *)arg->object, "db_full_path");
884  arg->object = (struct db_full_path *)NULL;
885  }
886 
887  return GED_OK;
888 }
889 
890 
891 /**
892  * "Expands" object arguments for a batch operation.
893  *
894  * meta_arg is replaced with a list of copies of src_objects, with
895  * certain meta_arg flags applied and/or consolidated with those of
896  * the source objects. Objects + offsets are converted to coordinates.
897  *
898  * Set GED_QUIET or GED_ERROR bits in 'flags' to suppress or enable
899  * output to ged_result_str, respectively.
900  *
901  * Returns GED_ERROR on failure, and GED_OK on success.
902  */
903 HIDDEN int
904 edit_arg_expand_meta(struct ged *gedp, struct edit_arg *meta_arg,
905  const struct edit_arg *src_objs, const int flags)
906 {
907  struct edit_arg *prototype;
908  struct edit_arg **dest;
909  const struct edit_arg *src;
910  const int noisy = (flags & GED_ERROR); /* side with verbosity */
911  int firstrun = 1;
912 
913  BU_ASSERT(!meta_arg->next); /* should be at end of list */
914 
915  /* repurpose meta_arg, so ptr-to-ptr isn't required */
916  edit_arg_duplicate(&prototype, meta_arg);
917  edit_arg_free_inner(meta_arg);
918  edit_arg_init(meta_arg);
919  dest = &meta_arg;
920 
921  for (src = src_objs; src; src = src->next, dest = &(*dest)->next) {
922  if (firstrun) {
923  firstrun = 0;
924  edit_arg_duplicate_in_place(*dest, src);
925  }
926  else
927  edit_arg_duplicate(dest, src);
928 
929  /* never use coords that target obj didn't include */
930  (*dest)->coords_used &= prototype->coords_used;
931  if (!((*dest)->coords_used & EDIT_COORDS_ALL)) {
932  if (noisy)
934  "coordinate filters for batch operator and target"
935  "objects result in no coordinates being used");
936  return GED_ERROR;
937  }
938 
939  /* respect certain type flags from the prototype/target obj */
940  (*dest)->type |= EDIT_TARGET_OBJ_BATCH_TYPES & prototype->type &
941  src->type;
942  (*dest)->type |= (EDIT_FROM | EDIT_TO) & prototype->type;
943 
944  if (edit_arg_to_coord(gedp, *dest, (vect_t *)NULL) == GED_ERROR)
945  return GED_ERROR;
946  }
947  return GED_OK;
948 }
949 
950 
951 /*
952  * Command helper functions
953  */
954 
955 
956 /**
957  * Initialize all command argument-pointer members to NULL.
958  */
959 HIDDEN void
960 edit_cmd_init(union edit_cmd *const subcmd)
961 {
962  struct edit_arg **arg_head;
963  int i = 1;
964 
965  arg_head = &subcmd->common.objects;
966  do
967  *arg_head = (struct edit_arg *)NULL;
968  while ((arg_head = subcmd->cmd->get_arg_head(subcmd, i++)) !=
969  &subcmd->common.objects);
970 }
971 
972 
973 /**
974  * Free any dynamically allocated argument nodes that may exist.
975  */
976 HIDDEN void
977 edit_cmd_free(union edit_cmd *const cmd)
978 {
979  struct edit_arg **arg_head;
980  int i = 0;
981 
982  arg_head = cmd->cmd->get_arg_head(cmd, i);
983  do {
984  if (*arg_head) {
985  edit_arg_free_all(*arg_head);
986  *arg_head = NULL;
987  }
988  } while ((arg_head = cmd->cmd->get_arg_head(cmd, ++i)) !=
989  &cmd->common.objects);
990 }
991 
992 
993 /**
994  * Perform a shallow copy of a subcommand's argument grouping.
995  */
996 HIDDEN void
997 edit_cmd_sduplicate(union edit_cmd *const dest,
998  const union edit_cmd *const src)
999 {
1000  struct edit_arg **src_head = NULL;
1001  struct edit_arg **dest_head;
1002  int i = 0;
1003 
1004  /* never try to duplicate dissimilar command types */
1005  BU_ASSERT_PTR(dest->cmd, ==, src->cmd);
1006 
1007  src_head = src->cmd->get_arg_head(src, i);
1008  do {
1009  dest_head = dest->cmd->get_arg_head(dest, i);
1010  *dest_head = *src_head;
1011  } while ((src_head = src->cmd->get_arg_head(src, ++i)) !=
1012  &src->common.objects);
1013 }
1014 
1015 
1016 /**
1017  * Sets any skipped vector elements to a reasonable default, sets
1018  * EDIT_COORDS_ALL on vector arguments, and converts relative offsets
1019  * to absolute positions. Expects all arguments except target objects
1020  * to have vector set. Only looks at the first set of args.
1021  *
1022  * XXX: This intentionally only looks at the first set of args. At
1023  * some point, it may be desirable to have the subcommand functions
1024  * (i.e. edit_<subcmd>_wrapper()) call this prior to execution, so
1025  * that some commands can expand their own vectors in an unusual ways.
1026  */
1027 HIDDEN int
1028 edit_cmd_expand_vectors(struct ged *gedp, union edit_cmd *const subcmd)
1029 {
1030  struct edit_arg **arg_head;
1031  vect_t src_v = VINIT_ZERO; /* where omitted points draw from */
1032  vect_t *kp_v = (vect_t *)NULL; /* 'from' point, aka keypoint */
1033  vect_t *to_v = (vect_t *)NULL; /* 'to' point */
1034  int i = 0;
1035 
1036  /* draw source vector from target object */
1037  arg_head = subcmd->cmd->get_arg_head(subcmd, i++);
1038  if (edit_arg_to_apparent_coord(gedp, *arg_head, &src_v) == GED_ERROR)
1039  return GED_ERROR;
1040 
1041  while ((arg_head = subcmd->cmd->get_arg_head(subcmd, i++)) !=
1042  &subcmd->common.objects) {
1043  if (!(*arg_head))
1044  continue;
1045 
1046  to_v = (*arg_head)->vector;
1047  if ((*arg_head)->type & EDIT_FROM) {
1048  kp_v = (*arg_head)->vector;
1049  if (!((*arg_head)->coords_used & EDIT_COORD_X))
1050  (*to_v)[0] = src_v[0];
1051  if (!((*arg_head)->coords_used & EDIT_COORD_Y))
1052  (*to_v)[1] = src_v[1];
1053  if (!((*arg_head)->coords_used & EDIT_COORD_Z))
1054  (*to_v)[2] = src_v[2];
1055  } else if ((*arg_head)->type & EDIT_REL_DIST) {
1056  /* convert to absolute position */
1057  BU_ASSERT(kp_v); /* edit_*_add_cl_args should set this */
1058  (*arg_head)->type &= ~EDIT_REL_DIST;
1059  if ((*arg_head)->coords_used & EDIT_COORD_X) {
1060  (*to_v)[0] += (*kp_v)[0];
1061  (*kp_v)[0] = src_v[0];
1062  } else /* no movement */
1063  (*to_v)[0] = (*kp_v)[0];
1064  if ((*arg_head)->coords_used & EDIT_COORD_Y) {
1065  (*to_v)[1] += (*kp_v)[1];
1066  (*kp_v)[1] = src_v[1];
1067  } else
1068  (*to_v)[1] = (*kp_v)[1];
1069  if ((*arg_head)->coords_used & EDIT_COORD_Z) {
1070  (*to_v)[2] += (*kp_v)[2];
1071  (*kp_v)[2] = src_v[2];
1072  } else
1073  (*to_v)[2] = (*kp_v)[2];
1074  kp_v = (vect_t *)NULL;
1075  } else {
1076  BU_ASSERT((*arg_head)->type &= ~EDIT_ABS_POS);
1077  if (!((*arg_head)->coords_used & EDIT_COORD_X) && kp_v)
1078  (*to_v)[0] = (*kp_v)[0];
1079  if (!((*arg_head)->coords_used & EDIT_COORD_Y) && kp_v)
1080  (*to_v)[1] = (*kp_v)[1];
1081  if (!((*arg_head)->coords_used & EDIT_COORD_Z) && kp_v)
1082  (*to_v)[2] = (*kp_v)[2];
1083  }
1084  (*arg_head)->coords_used |= EDIT_COORDS_ALL;
1085  }
1086  return GED_OK;
1087 }
1088 
1089 
1090 /**
1091  * Consolidates compatible arguments. If any of the arguments that are
1092  * being consolidated link to objects, they are converted to
1093  * coordinates. Only consolidatable arguments flagged with the same
1094  * argument type (or if the second arg has no type) that are under
1095  * the same argument head are consolidated.
1096  *
1097  * Common objects are left alone if skip_common_objects != 0.
1098  *
1099  * Returns GED_ERROR on failure, and GED_OK on success.
1100  */
1101 HIDDEN int
1102 edit_cmd_consolidate (struct ged *gedp, union edit_cmd *const subcmd,
1103  int skip_common_objects)
1104 {
1105  struct edit_arg **arg_head;
1106  struct edit_arg *prev_arg;
1107  struct edit_arg *cur_arg;
1108  struct edit_arg *next_arg;
1109  int i = 0;
1110 
1111  if (skip_common_objects)
1112  i = 1;
1113 
1114  while (((arg_head = subcmd->cmd->get_arg_head(subcmd, i++)) !=
1115  &subcmd->common.objects) || !skip_common_objects) {
1116  skip_common_objects = 1;
1117  prev_arg = *arg_head;
1118  if (!prev_arg)
1119  continue; /* only one element in list */
1120  for (cur_arg = prev_arg->next; cur_arg; cur_arg = cur_arg->next) {
1121  if (((prev_arg->coords_used & EDIT_COORDS_ALL) ^
1122  (cur_arg->coords_used & EDIT_COORDS_ALL)) &&
1123  (cur_arg->type == 0 || prev_arg->type == cur_arg->type) &&
1124  !(cur_arg->type & EDIT_TARGET_OBJ)) {
1125 
1126  /* It should be impossible to have no coords set. If
1127  * one arg has all coords set, it implies that the
1128  * other has none set.
1129  */
1130  BU_ASSERT((cur_arg->coords_used & EDIT_COORDS_ALL) !=
1131  EDIT_COORDS_ALL);
1132  BU_ASSERT((prev_arg->coords_used & EDIT_COORDS_ALL) !=
1133  EDIT_COORDS_ALL);
1134 
1135  /* convert objects to coords */
1136  if (cur_arg->object && edit_arg_to_coord(gedp, cur_arg,
1137  (vect_t *)NULL) == GED_ERROR)
1138  return GED_ERROR;
1139  if (prev_arg->object && edit_arg_to_coord(gedp, prev_arg,
1140  (vect_t *)NULL) == GED_ERROR)
1141  return GED_ERROR;
1142 
1143  /* consolidate */
1144  if (cur_arg->coords_used & EDIT_COORD_X) {
1145  prev_arg->coords_used |= EDIT_COORD_X;
1146  (*prev_arg->vector)[0] = (*cur_arg->vector)[0];
1147  }
1148  if (cur_arg->coords_used & EDIT_COORD_Y) {
1149  prev_arg->coords_used |= EDIT_COORD_Y;
1150  (*prev_arg->vector)[1] = (*cur_arg->vector)[1];
1151  }
1152  if (cur_arg->coords_used & EDIT_COORD_Z) {
1153  prev_arg->coords_used |= EDIT_COORD_Z;
1154  (*prev_arg->vector)[2] = (*cur_arg->vector)[2];
1155  }
1156 
1157  /* remove consolidated argument */
1158  next_arg = cur_arg->next;
1159  edit_arg_free(cur_arg);
1160  cur_arg = prev_arg;
1161  prev_arg->next = next_arg;
1162  } else {
1163  prev_arg = cur_arg; /* the args are incompatible */
1164  }
1165  }
1166  }
1167  return GED_OK;
1168 }
1169 
1170 
1171 /*
1172  * Command-specific functions.
1173  *
1174  * The translate command will be documented well to introduce the
1175  * concepts. Documentation of functions for other commands will be
1176  * minimal, since they are quite similar.
1177  *
1178  * To add a new command, you need to:
1179  * 1) add a struct to the union edit_cmd
1180  * 2) create 4 functions that
1181  * a) add args to build the command
1182  * b) get the next arg head in union edit_cmd (trivial)
1183  * c) perform the command
1184  * d) wrap the command, to alternatively accept a union
1185  * edit_cmd; perform any unusual pre-execution
1186  * changes (trivial)
1187  * 3) add command data/function pointers to the command table
1188  */
1189 
1190 
1191 /**
1192  * Rotate an object by specifying points.
1193  */
1194 HIDDEN int
1195 edit_rotate(struct ged *gedp, const vect_t * axis_from,
1196  const vect_t *axis_to, const vect_t *center,
1197  const vect_t *angle_origin, const vect_t *angle_from,
1198  const vect_t *angle_to, const struct db_full_path *path)
1199 {
1200  (void)gedp;
1201  (void)axis_from;
1202  (void)axis_to;
1203  (void)center;
1204  (void)angle_origin;
1205  (void)angle_from;
1206  (void)angle_to;
1207  (void)path;
1208  return GED_OK;
1209 }
1210 
1211 
1212 /**
1213  * Maps edit_arg fields to the subcommand function's arguments and
1214  * calls it.
1215  */
1216 HIDDEN int
1217 edit_rotate_wrapper(struct ged *gedp, const union edit_cmd *const cmd)
1218 {
1219  const vect_t *from_vp = (const vect_t *)cmd->rotate.ref_axis.from->vector;
1220  const vect_t *to_vp = (const vect_t *)cmd->rotate.ref_axis.to->vector;
1221  const vect_t *center_vp = (const vect_t *)cmd->rotate.center->vector;
1222  const vect_t *ang_origin_vp = (const vect_t *)cmd->rotate.ref_angle.origin->vector;
1223  const vect_t *ang_from_vp = (const vect_t *)cmd->rotate.ref_angle.from->vector;
1224  const vect_t *ang_to_vp = (const vect_t *)cmd->rotate.ref_angle.to->vector;
1225 
1226  return edit_rotate(gedp, from_vp, to_vp, center_vp, ang_origin_vp, ang_from_vp, ang_to_vp,
1227  cmd->rotate.objects->object);
1228 }
1229 
1230 
1231 /*
1232  * Add arguments to the command that were built from the cmd line.
1233  */
1234 HIDDEN int
1235 edit_rotate_add_cl_args(struct ged *gedp, union edit_cmd *const cmd,
1236  const int flags)
1237 {
1238  (void)gedp;
1239  (void)cmd;
1240  (void)flags;
1241  return GED_OK;
1242 }
1243 
1244 
1245 /**
1246  * Given an pointer to an argument head in the edit_cmd union, this
1247  * function will return the next argument head in the union.
1248  */
1249 HIDDEN struct edit_arg **
1250 edit_rotate_get_arg_head(const union edit_cmd *const cmd, int idx)
1251 {
1252 #define EDIT_ROTATE_ARG_HEADS_LEN 7
1253  const struct edit_arg **arg_heads[EDIT_ROTATE_ARG_HEADS_LEN];
1254 
1256 
1257  arg_heads[0] = (const struct edit_arg **)&cmd->rotate.objects;
1258  arg_heads[1] = (const struct edit_arg **)&cmd->rotate.ref_axis.from;
1259  arg_heads[2] = (const struct edit_arg **)&cmd->rotate.ref_axis.to;
1260  arg_heads[3] = (const struct edit_arg **)&cmd->rotate.center;
1261  arg_heads[4] = (const struct edit_arg **)&cmd->rotate.ref_angle.origin;
1262  arg_heads[5] = (const struct edit_arg **)&cmd->rotate.ref_angle.from;
1263  arg_heads[6] = (const struct edit_arg **)&cmd->rotate.ref_angle.to;
1264 
1265  return (struct edit_arg **)arg_heads[idx];
1266 }
1267 
1268 
1269 /**
1270  * Scale an object by specifying points.
1271  */
1272 int
1273 edit_scale(struct ged *gedp, const vect_t *scale_from,
1274  const vect_t *scale_to, const vect_t *center,
1275  const vect_t *factor_from, const vect_t *factor_to,
1276  const struct db_full_path * path)
1277 {
1278  (void)gedp;
1279  (void)scale_from;
1280  (void)scale_to;
1281  (void)center;
1282  (void)factor_from;
1283  (void)factor_to;
1284  (void)path;
1285  return GED_OK;
1286 }
1287 
1288 
1289 /**
1290  * Maps edit_arg fields to the subcommand function's arguments and
1291  * calls it.
1292  */
1293 HIDDEN int
1294 edit_scale_wrapper(struct ged *gedp, const union edit_cmd *const cmd)
1295 {
1296  const vect_t *from_vp = (const vect_t *)cmd->scale.ref_scale.from->vector;
1297  const vect_t *to_vp = (const vect_t *)cmd->scale.ref_scale.to->vector;
1298  const vect_t *center_vp = (const vect_t *)cmd->scale.center->vector;
1299  const vect_t *ref_from_vp = (const vect_t *)cmd->scale.ref_factor.from->vector;
1300  const vect_t *ref_to_vp = (const vect_t *)cmd->scale.ref_factor.to->vector;
1301 
1302  return edit_scale(gedp, from_vp, to_vp, center_vp, ref_from_vp, ref_to_vp,
1303  (const struct db_full_path *)cmd->scale.objects->object);
1304 }
1305 
1306 
1307 /*
1308  * Add arguments to the command that were built from the cmd line.
1309  */
1310 HIDDEN int
1311 edit_scale_add_cl_args(struct ged *gedp, union edit_cmd *const cmd,
1312  const int flags)
1313 {
1314  (void)gedp;
1315  (void)cmd;
1316  (void)flags;
1317  return GED_OK;
1318 }
1319 
1320 
1321 /**
1322  * Given an pointer to an argument head in the edit_cmd union, this
1323  * function will return the next argument head in the union.
1324  */
1325 HIDDEN struct edit_arg **
1326 edit_scale_get_arg_head(const union edit_cmd *const cmd, int idx)
1327 {
1328 #define EDIT_SCALE_ARG_HEADS_LEN 6
1329  const struct edit_arg **arg_heads[EDIT_SCALE_ARG_HEADS_LEN];
1330 
1331  idx %= EDIT_SCALE_ARG_HEADS_LEN;
1332 
1333  arg_heads[0] = (const struct edit_arg **)&cmd->scale.objects;
1334  arg_heads[1] = (const struct edit_arg **)&cmd->scale.ref_scale.from;
1335  arg_heads[2] = (const struct edit_arg **)&cmd->scale.ref_scale.to;
1336  arg_heads[3] = (const struct edit_arg **)&cmd->scale.center;
1337  arg_heads[4] = (const struct edit_arg **)&cmd->scale.ref_factor.from;
1338  arg_heads[5] = (const struct edit_arg **)&cmd->scale.ref_factor.to;
1339 
1340  return (struct edit_arg **)arg_heads[idx];
1341 }
1342 
1343 
1344 /**
1345  * Perform a translation on an object by specifying points.
1346  */
1347 HIDDEN int
1348 edit_translate(struct ged *gedp, const vect_t *const from,
1349  const vect_t *const to,
1350  const struct db_full_path *const path)
1351 {
1352  struct directory *d_to_modify = NULL;
1353  struct directory *d_obj = NULL;
1354  vect_t delta;
1355  struct rt_db_internal intern;
1356 
1357  VSUB2(delta, *to, *from);
1358  VSCALE(delta, delta, gedp->ged_wdbp->dbip->dbi_local2base);
1359  d_obj = DB_FULL_PATH_CUR_DIR(path);
1360 
1361  if (ged_path_validate(gedp, path) == GED_ERROR) {
1362  bu_vls_printf(gedp->ged_result_str, "path \"%s\" does not exist in"
1363  "the database", db_path_to_string(path));
1364  return GED_ERROR;
1365  }
1366 
1367  if (path->fp_len > 1) {
1368  /* A path was supplied; move obj instance only (obj's CWD
1369  * modified).
1370  */
1371  struct rt_comb_internal *comb;
1372  union tree *leaf_to_modify;
1373 
1374  d_to_modify = DB_FULL_PATH_GET(path, path->fp_len - (size_t)2);
1375  GED_DB_GET_INTERNAL(gedp, &intern, d_to_modify, (fastf_t *)NULL,
1377  comb = (struct rt_comb_internal *)intern.idb_ptr;
1378  leaf_to_modify = db_find_named_leaf(comb->tree, d_obj->d_namep);
1379 
1380  /* path is already validated */
1381  BU_ASSERT_PTR(leaf_to_modify, !=, TREE_NULL);
1382  if (!leaf_to_modify->tr_l.tl_mat) {
1383  leaf_to_modify->tr_l.tl_mat = (matp_t)bu_malloc(sizeof(mat_t),
1384  "mat_t block for edit_translate()");
1385  MAT_IDN(leaf_to_modify->tr_l.tl_mat);
1386  }
1387  MAT_DELTAS_ADD_VEC(leaf_to_modify->tr_l.tl_mat, delta);
1388  } else {
1389  /* No path given; move all obj instances (obj's entire tree
1390  * modified).
1391  */
1392  struct _ged_trace_data gtd;
1393  mat_t dmat;
1394  mat_t emat;
1395  mat_t tmpMat;
1396  mat_t invXform;
1397  point_t rpp_min;
1398  point_t rpp_max;
1399 
1400  d_to_modify = d_obj;
1401  if (_ged_get_obj_bounds2(gedp, 1, (const char **)&d_to_modify->d_namep,
1402  &gtd, rpp_min, rpp_max) == GED_ERROR)
1403  return GED_ERROR;
1404  if (!(d_to_modify->d_flags & RT_DIR_SOLID) &&
1405  (ged_get_obj_bounds(gedp, 1, (const char **)&d_to_modify->d_namep,
1406  1, rpp_min, rpp_max) == GED_ERROR))
1407  return GED_ERROR;
1408 
1409  MAT_IDN(dmat);
1410  MAT_DELTAS_VEC(dmat, delta);
1411 
1412  bn_mat_inv(invXform, gtd.gtd_xform);
1413  bn_mat_mul(tmpMat, invXform, dmat);
1414  bn_mat_mul(emat, tmpMat, gtd.gtd_xform);
1415 
1416  GED_DB_GET_INTERNAL(gedp, &intern, d_to_modify, emat,
1418  }
1419 
1420  RT_CK_DB_INTERNAL(&intern);
1421  GED_DB_PUT_INTERNAL(gedp, d_to_modify, &intern, &rt_uniresource,
1422  GED_ERROR);
1423  rt_db_free_internal(&intern);
1424  return GED_OK;
1425 }
1426 
1427 
1428 /**
1429  * Maps edit_arg fields to the subcommand function's arguments and
1430  * calls it. Provides an common interface, so that all subcommands
1431  * can use the same function pointer type. Ignores all edit_arg fields
1432  * other than vector, and the first object to operate on in the
1433  * objects edit_arg. Ignores all edit_arg->next arguments.
1434  */
1435 HIDDEN int
1436 edit_translate_wrapper(struct ged *gedp, const union edit_cmd *const cmd)
1437 {
1438  const vect_t *from = (const vect_t *)cmd->translate.ref_vector.from->vector;
1439  const vect_t *to = (const vect_t *)cmd->translate.ref_vector.to->vector;
1440  return edit_translate(gedp,
1441  (const vect_t * const)from,
1442  (const vect_t * const)to,
1443  (const struct db_full_path *)cmd->translate.objects->object);
1444 }
1445 
1446 
1447 /**
1448  * Add arguments to the command that were built from the cmd line.
1449  * All unique argument pointers in the command should be initialized
1450  * to NULL before using.
1451  *
1452  * Note: This command happens to only accept the standard command line
1453  * options, so others are ignored.
1454  */
1455 HIDDEN int
1456 edit_translate_add_cl_args(struct ged *gedp, union edit_cmd *const cmd,
1457  const int flags)
1458 {
1459  const int noisy = (flags & GED_ERROR); /* side with verbosity */
1460  struct edit_arg *cur_arg = cmd->cmd_line.args;
1461 
1462  BU_ASSERT_PTR(cur_arg, !=, (struct edit_arg *)NULL);
1463 
1464  if (cur_arg->type & EDIT_FROM) {
1465  /* if there isn't an EDIT_TO, this func shouldn't be called */
1466  BU_ASSERT_PTR(cur_arg->next, !=, (struct edit_arg *)NULL);
1467 
1468  /* disallow non-standard opts */
1469  if (cur_arg->cl_options[0] != '\0')
1470  goto err_option_unknown;
1471 
1472  cmd->translate.ref_vector.from = cur_arg;
1473  cur_arg = cmd->cmd_line.args = cmd->cmd_line.args->next;
1474  cmd->translate.ref_vector.from->next = NULL;
1475  }
1476 
1477  if ((cur_arg->type & EDIT_TO) || (cur_arg->type == 0)) {
1478  /* If there isn't an EDIT_TARGET_OBJECT, this func shouldn't
1479  * be called.
1480  */
1481  BU_ASSERT_PTR(cur_arg->next, !=, (struct edit_arg *)NULL);
1482 
1483  /* disallow non-standard opts */
1484  if (cur_arg->cl_options[0] != '\0')
1485  goto err_option_unknown;
1486 
1487  if (!(cur_arg->type & EDIT_ABS_POS)) {
1488  /* interpret 'TO' arg as a relative distance by default */
1489  cur_arg->type |= EDIT_REL_DIST;
1490 
1491  if (cur_arg->object) {
1492  if (noisy)
1494  "cannot use a reference object's coordinates"
1495  " as an offset distance");
1496  return GED_ERROR;
1497  }
1498  }
1499 
1500  cmd->translate.ref_vector.to = cur_arg;
1501  cur_arg = cmd->cmd_line.args = cmd->cmd_line.args->next;
1502  cmd->translate.ref_vector.to->next= NULL;
1503  } else {
1504  if (noisy) {
1505  if (cur_arg->type & EDIT_FROM)
1507  "too many \"FROM\" arguments");
1508  else
1509  bu_vls_printf(gedp->ged_result_str, "missing \"TO\" argument");
1510  }
1511  return GED_ERROR;
1512  }
1513 
1514  /* all that should be left is target objects; validate them */
1515  do {
1516  if (!(cur_arg->type & EDIT_TARGET_OBJ)) {
1517  if (noisy)
1518  bu_vls_printf(gedp->ged_result_str, "invalid syntax\n"
1519  "Usage: %s [help] | %s",
1520  cmd->cmd->name, cmd->cmd->usage);
1521  return GED_ERROR;
1522  }
1523 
1524  /* disallow non-standard opts */
1525  if (cur_arg->cl_options[0] != '\0')
1526  goto err_option_unknown;
1527  } while ((cur_arg = cur_arg->next));
1528 
1529  /* the default 'FROM' is the first target object */
1530  if (!cmd->translate.ref_vector.from) {
1532  cmd->translate.objects);
1533  cmd->translate.ref_vector.from->type &= ~EDIT_TARGET_OBJ;
1534  cmd->translate.ref_vector.from->type |= EDIT_FROM;
1535  }
1536 
1537  return GED_OK;
1538 
1539 err_option_unknown:
1540  if (noisy)
1541  bu_vls_printf(gedp->ged_result_str, "unknown option \"-%c\"",
1542  cur_arg->cl_options[0]);
1543  return GED_ERROR;
1544 }
1545 
1546 
1547 /**
1548  * Given an pointer to an argument head in the edit_cmd union, this
1549  * function will return the next argument head in the union.
1550  *
1551  * This function is used to traverse a commands arguments, without
1552  * needing to know their structure. edit_cmd.common.objects should be
1553  * used as the first argument head, to traverse the entire struct.
1554  *
1555  * XXX: Kind of dirty; haven't found a better way yet, though.
1556  */
1557 HIDDEN struct edit_arg **
1558 edit_translate_get_arg_head(const union edit_cmd *const cmd, int idx)
1559 {
1560 #define EDIT_TRANSLATE_ARG_HEADS_LEN 3
1561  const struct edit_arg **arg_heads[EDIT_TRANSLATE_ARG_HEADS_LEN];
1562 
1564 
1565  arg_heads[0] = (const struct edit_arg **)&cmd->translate.objects;
1566  arg_heads[1] = (const struct edit_arg **)&cmd->translate.ref_vector.from;
1567  arg_heads[2] = (const struct edit_arg **)&cmd->translate.ref_vector.to;
1568 
1569  return (struct edit_arg **)arg_heads[idx];
1570 }
1571 
1572 
1573 /*
1574  * Table of edit command data/functions
1575  */
1576 static const struct edit_cmd_tab edit_cmds[] = {
1577  {"help", (char *)NULL, "[subcommand]", "[subcommand]",
1578  EDIT_CMD_ENABLE, NULL, NULL, NULL
1579 #define EDIT_CMD_HELP 0 /* idx of "help" in edit_cmds */
1580  },
1581  {"rotate", "R",
1582  "[-R] [AXIS] [CENTER] ANGLE OBJECT ...",
1583  "[-R] [[[-n] -k {AXIS_FROM_OBJECT | AXIS_FROM_POS}]\n"
1584  "[[-n] [-a | -r] {AXIS_TO_OBJECT | AXIS_TO_POS}]]\n"
1585  "[[-n] -c {CENTER_OBJECT | CENTER_POS}]\n"
1586  "[[-n] -O {ANGLE_ORIGIN_OBJECT| ANGLE_ORIGIN_POS}]\n"
1587  "[[-n] -k {ANGLE_FROM_OBJECT | ANGLE_FROM_POS}]\n"
1588  "[-n | -o] [-a | -r | -d]"
1589  "{ANGLE_TO_OBJECT | ANGLE_TO_POS}} OBJECT ...",
1594  },
1595  {"scale", (char *)NULL,
1596  "[SCALE] [CENTER] FACTOR OBJECT ...",
1597  "[[[-n] -k {SCALE_FROM_OBJECT | SCALE_FROM_POS}]\n"
1598  "[-n] [-a | -r] {SCALE_TO_OBJECT | SCALE_TO_POS}]\n"
1599  "[[-n] -c {CENTER_OBJECT | CENTER_POS}]\n"
1600  "[[-n] -k {FACTOR_FROM_OBJECT | FACTOR_FROM_POS}]\n"
1601  "[-n] [-a | -r] {FACTOR_TO_OBJECT | FACTOR_TO_POS}"
1602  " OBJECT ...",
1607  },
1608  {"translate", (char *)NULL,
1609  "[FROM] TO OBJECT ...",
1610  "[[-n] -k {FROM_OBJECT | FROM_POS}]\n"
1611  "[-n] [-a | -r] {TO_OBJECT | TO_POS} OBJECT ...",
1616  },
1617  {(char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, EDIT_CMD_DISABLE,
1618  NULL, NULL, NULL
1619  }
1620 };
1621 
1622 
1623 /*
1624  * Command agnostic functions
1625  */
1626 
1627 
1628 /**
1629  * A wrapper for the edit commands. It adds the capability to
1630  * perform batch operations, and accepts objects and distances in
1631  * addition to coordinates. As a side effect, arguments flagged
1632  * with EDIT_USE_TARGETS will be replaced (expanded) in performing
1633  * batch commands.
1634  *
1635  * Returns GED_ERROR on failure, and GED_OK on success.
1636  *
1637  * Note that this function ignores most argument type flags, since
1638  * it's expected that all args will be in the proper locations in the
1639  * given command struct. An exception is made for
1640  * EDIT_TARGET_OBJ_BATCH_TYPES, which is respected since certain flags
1641  * may propagate in batch operations. Coordinate flags are always
1642  * respected.
1643  *
1644  * If batch arguments are to be used, they should be either:
1645  * a) the first and only argument in the given argument head
1646  * or
1647  * b) expanded prior to being passed to this function
1648  * This is because an expansion of a batch character leads to an
1649  * argument head having any prior nodes, *plus* the expanded nodes.
1650  * If there were any prior nodes, the expansion would cause a
1651  * lopsided set of arguments, which should result in a BU_ASSERT
1652  * failure.
1653  */
1654 HIDDEN int
1655 edit(struct ged *gedp, union edit_cmd *const subcmd)
1656 {
1657  struct edit_arg **arg_head;
1658  struct edit_arg *prev_arg;
1659  struct edit_arg *cur_arg;
1660  union edit_cmd subcmd_iter; /* to iterate through subcmd args */
1661  int i = 0;
1662  int num_target_objs = 0;
1663  int num_args_set = 0;
1664 
1665  /* Check all arg nodes in subcmd->common.objects first. They may
1666  * be copied later, if there are any batch modifiers to expand.
1667  */
1668  arg_head = subcmd->cmd->get_arg_head(subcmd, i++);
1669  for (cur_arg = *arg_head; cur_arg; cur_arg = cur_arg->next) {
1670  /* target objects must be... objects */
1671  BU_ASSERT(cur_arg->object);
1672 
1673  /* cmd line opts should have been handled/removed */
1674  BU_ASSERT(cur_arg->cl_options[0] == '\0');
1675 
1676  ++num_target_objs;
1677  }
1678 
1679  /* process all other arg nodes */
1680  while ((arg_head = subcmd->cmd->get_arg_head(subcmd, i++)) != &subcmd->common.objects) {
1681  num_args_set = 0;
1682  prev_arg = NULL;
1683  for (cur_arg = *arg_head; cur_arg; cur_arg = cur_arg->next) {
1684 
1685  /* cmd line opts should have been handled/removed */
1686  BU_ASSERT(cur_arg->cl_options[0] == '\0');
1687  prev_arg = cur_arg;
1688 
1689  if (cur_arg->type & EDIT_USE_TARGETS) {
1690  if (edit_arg_expand_meta(gedp, cur_arg, subcmd->common.objects,
1691  GED_ERROR) == GED_ERROR)
1692  return GED_ERROR;
1693  num_args_set += num_target_objs;
1694  break; /* batch opertor should be last arg */
1695  }
1696  if (cur_arg->object) {
1697  if (edit_arg_to_coord(gedp, cur_arg, (vect_t *)NULL) ==
1698  GED_ERROR)
1699  return GED_ERROR;
1700  }
1701  ++num_args_set;
1702  }
1703 
1704  /* All argument lists should be the same length as the common
1705  * objects list. Duplicate the last argument until this is so.
1706  */
1707  if (prev_arg) {
1708  while (num_args_set < num_target_objs) {
1709  edit_arg_duplicate(&prev_arg->next, prev_arg);
1710  prev_arg = prev_arg->next;
1711  ++num_args_set;
1712  }
1713  BU_ASSERT(num_args_set == num_target_objs);
1714  }
1715  }
1716 
1717  /* Create a copy to iterate over groups of batch args; note that
1718  * the copy is shallow and *must not be freed*.
1719  */
1720  subcmd_iter.cmd = subcmd->cmd;
1721  edit_cmd_init(&subcmd_iter);
1722  edit_cmd_sduplicate(&subcmd_iter, subcmd);
1723 
1724  /* Iterate over each set of batch args, executing the subcmd once
1725  * for each level of edit_arg nodes. The number of common objects
1726  * determines how many times the command is run.
1727  */
1728  do {
1729  if (edit_cmd_expand_vectors(gedp, &subcmd_iter) == GED_ERROR)
1730  return GED_ERROR;
1731  if (subcmd_iter.cmd->exec(gedp, &subcmd_iter) == GED_ERROR)
1732  return GED_ERROR;
1733 
1734  /* set all heads to the next arguments in their lists */
1735  num_args_set = 0;
1736  i = 0; /* reinit for get_arg_head() */
1737  while (((arg_head =
1738  subcmd_iter.cmd->get_arg_head(&subcmd_iter, i)) !=
1739  &subcmd_iter.common.objects) || (i == 0)) {
1740  ++i;
1741  if (*arg_head && (*arg_head)->next) {
1742  *arg_head = (*arg_head)->next;
1743  ++num_args_set;
1744  }
1745  }
1746  } while (num_args_set != 0);
1747 
1748  return GED_OK;
1749 }
1750 
1751 
1752 /**
1753  * Converts a string to an existing edit_arg. See subcommand manuals
1754  * for examples of acceptable argument strings.
1755  *
1756  * Set GED_QUIET or GED_ERROR bits in 'flags' to suppress or enable
1757  * output to ged_result_str, respectively.
1758  *
1759  * Returns GED_ERROR on failure, and GED_OK on success.
1760  */
1761 HIDDEN int
1762 edit_str_to_arg(struct ged *gedp, const char *str, struct edit_arg *arg,
1763  const int flags)
1764 {
1765  const int noisy = (flags & GED_ERROR); /* side with verbosity */
1766  char const *first_slash = NULL;
1767  char *endchr = NULL; /* for strtod's */
1768  vect_t coord;
1769 
1770  /*
1771  * Here is how numbers that are also object names are interpreted:
1772  * if an object is not yet set in *arg, try to treat the number as
1773  * an object first. If the user has an object named, say '5', they
1774  * can avoid using the object named 5 by specifying 5.0 or
1775  * something. If an arg->object has already been set, then the
1776  * number was most likely intended to be an offset, so interpret
1777  * it as as such.
1778  */
1779 
1780  if (!arg->object && !(arg->type & EDIT_USE_TARGETS) && !arg->vector) {
1781 
1782  /* batch operators; objects with same name will be masked */
1783  if (BU_STR_EQUAL(str, ".")) {
1784  arg->type |= EDIT_USE_TARGETS;
1785  return GED_OK;
1786  }
1787 
1788  /* an arg with a slash is always interpreted as a path */
1789  first_slash = strchr(str, '/');
1790  if (first_slash) {
1791  char const *path_start;
1792  char const *path_end;
1793 
1794  /* position start after leading slashes */
1795  path_start = str;
1796  while (path_start[0] == '/')
1797  ++path_start;
1798 
1799  /* position end before trailing slashes */
1800  path_end = path_start + strlen(path_start) - (size_t)1;
1801  while (path_end[0] == '/')
1802  --path_end;
1803 
1804  if (path_end < path_start) {
1805  /* path contained nothing but '/' char(s) */
1806  if (noisy)
1807  bu_vls_printf(gedp->ged_result_str, "cannot use root path "
1808  "alone");
1809  return GED_ERROR;
1810  }
1811 
1812  goto convert_obj;
1813  }
1814 
1815  /* it may still be an obj, so quietly check db for obj name */
1816  if (db_lookup(gedp->ged_wdbp->dbip, str, LOOKUP_QUIET) != RT_DIR_NULL)
1817  goto convert_obj;
1818  }
1819 
1820  /* if string is a number, fall back to interpreting it as one */
1821  coord[0] = strtod(str, &endchr);
1822  if (*endchr != '\0') {
1823  if (noisy)
1824  bu_vls_printf(gedp->ged_result_str, "unrecognized argument, \"%s\"",
1825  str);
1826  return GED_ERROR;
1827  }
1828  if (!arg->vector)
1829  BU_ALLOC(arg->vector, vect_t);
1830 
1831  /* Attempt to interpret/record the number as the next unset X, Y,
1832  * or Z coordinate/position.
1833  */
1834  if (((arg->coords_used & EDIT_COORDS_ALL) == EDIT_COORDS_ALL) ||
1835  arg->object || (arg->type & EDIT_USE_TARGETS)) {
1836 
1837  /* set the first coordinate that isn't set */
1838  if (!(arg->coords_used & EDIT_COORD_IS_SET_X)) {
1839  (*arg->vector)[0] = coord[0];
1841  } else if (!(arg->coords_used & EDIT_COORD_IS_SET_Y)) {
1842  (*arg->vector)[1] = coord[0];
1844  } else if (!(arg->coords_used & EDIT_COORD_IS_SET_Z)) {
1845  (*arg->vector)[2] = coord[0];
1847  } else {
1848  if (noisy)
1849  bu_vls_printf(gedp->ged_result_str, "too many consecutive"
1850  " coordinates: %f %f %f %f ...",
1851  (*arg->vector)[0], (*arg->vector)[1],
1852  (*arg->vector)[2], coord[0]);
1853  return GED_ERROR;
1854  }
1855  } else {
1856  /* only set specified coord */
1857  BU_ASSERT((arg->coords_used & EDIT_COORDS_ALL) != 0);
1858  if (arg->coords_used & EDIT_COORD_X) {
1859  (*arg->vector)[0] = coord[0];
1861  } else if (arg->coords_used & EDIT_COORD_Y) {
1862  (*arg->vector)[1] = coord[0];
1864  } else if (arg->coords_used & EDIT_COORD_Z) {
1865  (*arg->vector)[2] = coord[0];
1867  }
1868  }
1869  return GED_OK;
1870 
1871 convert_obj:
1872  /* convert string to path/object */
1873  BU_ALLOC(arg->object, struct db_full_path);
1874  if (db_string_to_path(arg->object, gedp->ged_wdbp->dbip,
1875  str)) {
1876  db_free_full_path(arg->object);
1877  bu_free((void *)arg->object, "db_string_to_path");
1878  arg->object = (struct db_full_path *)NULL;
1879  if (noisy)
1880  bu_vls_printf(gedp->ged_result_str, "one of the objects in"
1881  " the path \"%s\" does not exist", str);
1882  return GED_ERROR;
1883  }
1884  if (ged_path_validate(gedp, arg->object) == GED_ERROR) {
1885  db_free_full_path(arg->object);
1886  bu_free((void *)arg->object, "db_string_to_path");
1887  arg->object = (struct db_full_path *)NULL;
1888  if (noisy)
1889  bu_vls_printf(gedp->ged_result_str, "path \"%s\" does not exist in"
1890  "the database", str);
1891  return GED_ERROR;
1892  }
1893  return GED_OK;
1894 }
1895 
1896 
1897 /**
1898  * Converts as much of an array of strings as possible to a single
1899  * edit_arg. Both argc and argv are modified to be past the matching
1900  * arguments. See subcommand manuals for examples of acceptable
1901  * argument strings.
1902  *
1903  * Set GED_QUIET or GED_ERROR bits in 'flags' to suppress or enable
1904  * output to ged_result_str, respectively. Note that output is always
1905  * suppressed after the first string is successfully converted.
1906  *
1907  * Returns GED_OK if at least one string is converted, otherwise
1908  * GED_ERROR is returned.
1909  *
1910  */
1911 HIDDEN int
1912 edit_strs_to_arg(struct ged *gedp, int *argc, const char **argv[],
1913  struct edit_arg *arg, int flags)
1914 {
1915  int ret = GED_ERROR;
1916  int len;
1917  int idx;
1918 
1919  while (*argc >= 1) {
1920 
1921  /* skip options */
1922  idx = 0;
1923  len = strlen((*argv)[0]);
1924  if ((**argv)[0] == '-') {
1925  if (len == 2 && !isdigit((int)(**argv)[1]))
1926  break;
1927  if (len > 2 && !isdigit((int)(**argv)[1]))
1928  /* option/arg pair with no space, i.e. "-ksph.s" */
1929  idx = 2;
1930  }
1931 
1932  if (edit_str_to_arg(gedp, &(**argv)[idx], arg, flags) == GED_ERROR)
1933  break;
1934 
1935  ret = GED_OK;
1936  flags = GED_QUIET; /* only first conv attempt can be noisy */
1937  --(*argc);
1938  ++(*argv);
1939  }
1940 
1941  /* If all EDIT_COORDS_ALL are set, and at least one other flag, it
1942  * implies that the coords were in the '[x [y [z]]]" format. Set
1943  * coords used to whatever coords are actually set.
1944  */
1945  if (((arg->coords_used & EDIT_COORDS_ALL) == EDIT_COORDS_ALL) &&
1946  (arg->coords_used & ~EDIT_COORDS_ALL))
1947  arg->coords_used >>= 3;
1948 
1949  /* these flags are only for internal use */
1950  /* FIXME: exactly why they should be internalized, and not
1951  * edit_arg flags */
1954  return ret;
1955 }
1956 
1957 
1958 /**
1959  * A command line interface to the edit commands. Will handle any new
1960  * commands without modification. Validates as much as possible in a
1961  * single pass, without going back over the arguments list. Further,
1962  * more specific, validation is performed by edit().
1963  */
1964 int
1965 ged_edit(struct ged *gedp, int argc, const char *argv[])
1966 {
1967  const char *const cmd_name = argv[0];
1968  union edit_cmd subcmd;
1969  const char *subcmd_name = NULL;
1970  struct edit_arg *cur_arg = NULL;
1971  struct edit_arg *keypoint = NULL;
1972  static const char *const usage = "[subcommand] [args]";
1973  int idx_cur_opt = 0; /* pos in options array for current arg */
1974  int conv_flags = 0; /* for edit_strs_to_arg */
1975  int i; /* iterator */
1976  int c; /* for bu_getopt */
1977  int allow_subopts = 0; /* false(=0) when a subopt is bad syntax */
1978  int ret;
1979 
1982  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
1983 
1984  /* initialize result */
1985  bu_vls_trunc(gedp->ged_result_str, 0);
1986 
1987  /* initialize the subcommand */
1988  subcmd.cmd = (const struct edit_cmd_tab *)NULL;
1989 
1990  /*
1991  * Validate command name
1992  */
1993 
1994  /* FIXME: usage/help messages for subcommands should contain the
1995  * name of the 'parent' command when necessary: i.e.: 'edit
1996  * translate' rather than just 'translate'. Also, the help option
1997  * of subcommands is not displayed properly; it should display
1998  * when command is called directly, i.e. 'translate', but not
1999  * 'edit translate'
2000  */
2001 
2002  for (i = 0; edit_cmds[i].name; ++i) {
2003  /* search for command name in the table */
2004  if (BU_STR_EQUAL(edit_cmds[i].name, cmd_name)) {
2005  subcmd_name = cmd_name;
2006  /* save the name for a string comparison later */
2007  subcmd.cmd = &edit_cmds[i];
2008  /* match of cmd name takes precedence over match of subcmd
2009  * name
2010  */
2011  break;
2012  }
2013  /* interpret first arg as a cmd, and search for it in table */
2014  if (!subcmd_name && argc > 1 &&
2015  BU_STR_EQUAL(edit_cmds[i].name, argv[1])) {
2016  subcmd_name = argv[1];
2017  subcmd.cmd = &edit_cmds[i];
2018  }
2019  }
2020 
2021  if (subcmd_name == cmd_name) { /* ptr cmp */
2022  /* command name is serving as the subcommand */
2023  --argc;
2024  ++argv;
2025  } else if (subcmd.cmd) {
2026  /* first arg is the subcommand */
2027  argc -= 2;
2028  argv += 2;
2029  } else {
2030  /* no subcommand was found */
2031  ret = GED_HELP;
2032 
2033  if (argc > 1) {
2034  /* no arguments accepted without a subcommand */
2035  bu_vls_printf(gedp->ged_result_str, "unknown subcommand \"%s\"\n",
2036  argv[1]);
2037  ret = GED_ERROR;
2038  }
2039 
2040  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s"
2041  "\nAvailable subcommands: ", cmd_name, usage);
2042  for (i = 0; edit_cmds[i].name; ++i)
2043  if (edit_cmds[i].enabled)
2044  bu_vls_printf(gedp->ged_result_str, "%s ", edit_cmds[i].name);
2045  return ret;
2046  }
2047 
2048  if (subcmd.cmd == NULL) {
2049  bu_vls_printf(gedp->ged_result_str, "subcommand \"%s\""
2050  " is disabled", subcmd_name);
2051  return GED_ERROR;
2052  }
2053 
2054  /*
2055  * Subcommand help system
2056  */
2057 
2058  /* switch on idx of subcmd.cmd in edit_cmds[] */
2059  switch (subcmd.cmd - edit_cmds) {
2060  case EDIT_CMD_HELP:
2061  if (argc == 0) {
2062  /* get generic help */
2063  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s\n",
2064  subcmd.cmd->name, subcmd.cmd->usage);
2065  bu_vls_printf(gedp->ged_result_str, "Available subcommands: ");
2066  for (i = 0; edit_cmds[i].name; ++i)
2067  if (edit_cmds[i].enabled)
2068  bu_vls_printf(gedp->ged_result_str, "%s ",
2069  edit_cmds[i].name);
2070  return GED_HELP;
2071  } else {
2072  /* get long usage string for a specific command */
2073  for (i = 0; edit_cmds[i].name; ++i)
2074  /* search for command name in the table */
2075  if (BU_STR_EQUAL(edit_cmds[i].name, argv[0]))
2076  break; /* for loop */
2077 
2078  if (!edit_cmds[i].name) {
2080  "unknown subcommand \"%s\"\n",
2081  argv[0]);
2083  "Available subcommands: ");
2084  for (i = 0; edit_cmds[i].name; ++i)
2085  if (edit_cmds[i].enabled)
2086  bu_vls_printf(gedp->ged_result_str, "%s ",
2087  edit_cmds[i].name);
2088  return GED_ERROR;
2089  } else /* point to the cmd we want help for */
2090  subcmd.cmd = &edit_cmds[i];
2091  goto get_full_help;
2092  }
2093  default:
2094  if (argc == 0) {
2095  /* no args to subcommand; must want usage */
2096  bu_vls_printf(gedp->ged_result_str, "Usage: %s [help] | %s",
2097  subcmd.cmd->name, subcmd.cmd->usage);
2098  return GED_HELP;
2099  }
2100 
2101  /* Handle "subcmd help" (identical to "help subcmd"),
2102  * but only if there are no more args; would rather mask
2103  * the help system with an object that happened to be
2104  * named "help" than the other way around. This syntax is
2105  * needed to access the help system when a subcmd is the
2106  * calling command.
2107  */
2108  if (argc == 1 &&
2109  BU_STR_EQUAL(edit_cmds[EDIT_CMD_HELP].name,
2110  argv[0])) {
2111  goto get_full_help;
2112  }
2113  break;
2114 
2115  get_full_help:
2117  "Usage: %s [help] | %s\n\n%s [help] | %s",
2118  subcmd.cmd->name, subcmd.cmd->usage,
2119  subcmd.cmd->name, subcmd.cmd->help);
2120  return GED_HELP;
2121  }
2122 
2123  /* Now that the cmd type is known (and wasn't "help"), we can
2124  * initialize the subcmd's arguments. From here on out,
2125  * edit_cmd_free() must be called before exiting.
2126  */
2127  edit_cmd_init(&subcmd);
2128 
2129  BU_ALLOC(subcmd.cmd_line.args, struct edit_arg);
2130  edit_arg_init(subcmd.cmd_line.args);
2131  cur_arg = subcmd.cmd_line.args;
2132 
2133  /*
2134  * Parse all subcmd args and pass to edit()
2135  */
2136 
2137  /*
2138  * The object of the game is to remain agnostic of unique aspects
2139  * of argument structures of subcommands (i.e. inside the edit_cmd
2140  * union). Therefore, we will simply link all of the arguments
2141  * together with edit_arg structs for fuller parsing elsewhere.
2142  *
2143  * There are, however, a several things that are standardized for
2144  * each command (and for any newly added command).
2145  * 1) interpretation of nonstandard options:
2146  * a) nonstandard options (not -k/-a/-r/-x/-y/-z)
2147  * that *precede* either an argument specifier
2148  * (-k/-a/-r) or an option (-n), modify the argument
2149  * specifier's interpretation
2150  * b) all other nonstandard options are considered argument
2151  * specifiers themselves
2152  * c) unique global options are not recognized at this
2153  * point; therefore, they will be recorded in the same
2154  * way as nonstandard options that modify argument
2155  * specifiers (a, above), and parsed by the subcommand's
2156  * routines.
2157  * 2) keypoints ('FROM' arg options) are always preceded by
2158  * '-k'
2159  * 3) keypoints are all considered optional as far as this
2160  * function is concerned
2161  * 4) if a keypoint is specified, the argument is the first in
2162  * a pair; therefore a matching 'TO' argument is required
2163  * 5) any object specification string may:
2164  * a) contain a full path:[PATH/]OBJECT
2165  * b) use an offset: [x [y [z]]] ('-x' style not supported
2166  * in this context)
2167  * c) be used for a specific coordinate: -x/-y/-z OBJECT
2168  * d) be used for a specific coordinate and use an offset
2169  * simultaneously; ex: -z OBJECT 5 0 2 (note that 5 and
2170  * 0 are merely placeholders in this context)
2171  * 6) the batch object substitution character may be used as
2172  * an argument to -k/-a/-r ("." at the time of writing)
2173  * 7) at least one object must be operated on
2174  * 8) the last argument is a list of objects to be operated on
2175  */
2176 
2177  /* no options are required by default, so quietly look for args */
2178  while (edit_strs_to_arg(gedp, &argc, &argv, cur_arg, GED_QUIET) !=
2179  GED_ERROR) {
2180  if (argc == 0) {
2181  if (edit_arg_is_empty(subcmd.cmd_line.args) == GED_OK) {
2182  edit_arg_free(subcmd.cmd_line.args);
2183  subcmd.cmd_line.args = NULL;
2184  }
2185 
2186  cur_arg = subcmd.cmd_line.args;
2187  if (cur_arg && cur_arg->next) {
2188  cur_arg->type |= EDIT_TO;
2189  cur_arg = cur_arg->next;
2190  }
2191 
2192  /* parsing is done and there were no options, so all args
2193  * after the first arg should be a target obj
2194  */
2195  for (; cur_arg; cur_arg = cur_arg->next) {
2196  if (!(cur_arg->object)) {
2198  "expected only objects after first arg");
2199  edit_cmd_free(&subcmd);
2200  return GED_ERROR;
2201  }
2202  cur_arg->type |= EDIT_TARGET_OBJ;
2203  }
2204 
2205  /* let cmd specific func validate/move args to proper
2206  * locations
2207  */
2208  if (subcmd.cmd->add_cl_args(gedp, &subcmd, GED_ERROR) ==
2209  GED_ERROR)
2210  return GED_ERROR;
2211  ret = edit(gedp, &subcmd);
2212  edit_cmd_free(&subcmd);
2213  return ret;
2214  }
2215  cur_arg = edit_arg_postfix_new(subcmd.cmd_line.args);
2216  }
2217 
2218  /* All leading args are parsed. If we're not not at an option,
2219  * then there is a bad arg. Let the conversion function cry about
2220  * what it choked on.
2221  */
2222  if (strlen(argv[0]) > 1 && ((*argv)[0] != '-') && isdigit((int)(*argv)[1])) {
2223  ret = edit_strs_to_arg(gedp, &argc, &argv, cur_arg, GED_ERROR);
2224  edit_cmd_free(&subcmd);
2225  BU_ASSERT(ret == GED_ERROR);
2226  return GED_ERROR;
2227  }
2228 
2229  bu_optind = 1; /* re-init bu_getopt() */
2230  bu_opterr = 0; /* suppress errors; accept unknown options */
2231  ++argc; /* bu_getopt doesn't expect first element to be an arg */
2232  --argv;
2233  while ((c = bu_getopt(argc, (char * const *)argv, ":n:k:a:r:x:y:z:"))
2234  != -1) {
2235  if (bu_optind >= argc) {
2236  /* last element is an option */
2238  "No OBJECT provided; nothing to operate on");
2239  edit_cmd_free(&subcmd);
2240  return GED_ERROR;
2241  }
2242  if (idx_cur_opt >= EDIT_MAX_ARG_OPTIONS) {
2243  bu_vls_printf(gedp->ged_result_str, "too many options given, \"");
2244  for (i = 0; i < EDIT_MAX_ARG_OPTIONS; ++i)
2245  bu_vls_printf(gedp->ged_result_str, "-%c ",
2246  cur_arg->cl_options[i]);
2247  bu_vls_printf(gedp->ged_result_str, "-%c\"", c);
2248  edit_cmd_free(&subcmd);
2249  return GED_ERROR;
2250  }
2251 
2252  conv_flags = GED_ERROR;
2253  switch (c) {
2254  case 'n': /* use natural coordinates of object */
2255  conv_flags = GED_QUIET;
2256  allow_subopts = 0;
2257  break;
2258  case 'x': /* singular coord specif. sub-opts */
2259  case 'y':
2260  case 'z':
2261  idx_cur_opt = 0;
2262  if (!bu_optarg)
2263  goto err_missing_arg;
2264  if ((strlen(bu_optarg) > 1) && (bu_optarg[0] == '-') &&
2265  (!isdigit((int)bu_optarg[1])))
2266  goto err_missing_arg;
2267  if (!allow_subopts) {
2268  bu_vls_printf(gedp->ged_result_str, "-%c must follow an"
2269  " argument specification option", c);
2270  edit_cmd_free(&subcmd);
2271  return GED_ERROR;
2272  }
2273  break;
2274  case 'k': /* standard arg specification options */
2275  case 'a':
2276  case 'r':
2277  idx_cur_opt = 0;
2278  allow_subopts = 1;
2279  if (!bu_optarg)
2280  goto err_missing_arg;
2281  if ((strlen(bu_optarg) > 1) && (bu_optarg[0] == '-')) {
2282  switch (bu_optarg[1]) {
2283  case 'x':
2284  case 'y':
2285  case 'z':
2286  /* the only acceptable sub-options here */
2287  conv_flags = GED_QUIET;
2288  break;
2289  default:
2290  if (!isdigit((int)bu_optarg[1]))
2291  goto err_missing_arg;
2292  }
2293  }
2294  break;
2295  case '?': /* nonstandard or unknown option */
2296  allow_subopts = 1;
2297  c = bu_optopt;
2298  if (!bu_optarg)
2299  if (!isprint(c)) {
2301  "Unknown option character '\\x%x'", c);
2302  edit_cmd_free(&subcmd);
2303  return GED_ERROR;
2304  }
2305 
2306  /* next element may be an arg */
2307  conv_flags = GED_QUIET;
2308 
2309  /* record opt for validation/processing by subcmd */
2310  cur_arg->cl_options[idx_cur_opt] = c;
2311  ++idx_cur_opt;
2312  break;
2313  case ':':
2314  goto err_missing_arg;
2315  }
2316 
2317  /* set flags for standard options */
2318  switch (c) {
2319  case 'x':
2320  cur_arg->coords_used &= EDIT_COORD_X;
2321  break;
2322  case 'y':
2323  cur_arg->coords_used &= EDIT_COORD_Y;
2324  break;
2325  case 'z':
2326  cur_arg->coords_used &= EDIT_COORD_Z;
2327  break;
2328  case 'k':
2329  cur_arg->type |= EDIT_FROM;
2330  keypoint = cur_arg;
2331  break;
2332  case 'a':
2333  cur_arg->type |= EDIT_TO | EDIT_ABS_POS;
2334  keypoint = NULL;
2335  break;
2336  case 'r':
2337  cur_arg->type |= EDIT_TO | EDIT_REL_DIST;
2338  keypoint = NULL;
2339  break;
2340  case 'n':
2341  cur_arg->type |= EDIT_NATURAL_ORIGIN;
2342  break;
2343  default:
2344  break;
2345  }
2346 
2347  /* move to current arg */
2348  argc -= 2;
2349  argv += 2;
2350  BU_ASSERT(argc > 0);
2351 
2352  /* convert next element to an arg */
2353  if (edit_strs_to_arg(gedp, &argc, &argv, cur_arg, conv_flags) ==
2354  GED_ERROR) {
2355  if (conv_flags & GED_ERROR) {
2356  edit_cmd_free(&subcmd);
2357  return GED_ERROR;
2358  }
2359  } else {
2360  /* init for next arg */
2361  if (argc == 0)
2362  break; /* no more args */
2363  cur_arg = edit_arg_postfix_new(subcmd.cmd_line.args);
2364  }
2365 
2366  /* FIXME: It might take some time to make this work. */
2367  if ((cur_arg->type & EDIT_TARGET_OBJ) &&
2368  ((cur_arg->coords_used & EDIT_COORDS_ALL) != EDIT_COORDS_ALL)) {
2370  "using the batch operator to specify individual"
2371  " coordinates is not yet supported");
2372  edit_cmd_free(&subcmd);
2373  return GED_ERROR;
2374  }
2375 
2376  /* conversion moves argc/argv, so re-init bu_getopt() */
2377  bu_optind = 1;
2378 
2379  /* move to before next supposed option */
2380  ++argc;
2381  --argv;
2382  }
2383 
2384  if (keypoint) {
2386  "a keypoint is missing its matching 'TO' argument");
2387  edit_cmd_free(&subcmd);
2388  return GED_ERROR;
2389  }
2390 
2391  /* get final/trailing args */
2392  ++argv;
2393  --argc;
2394  while (argc > 0) {
2395  if (edit_strs_to_arg(gedp, &argc, &argv, cur_arg, GED_ERROR) ==
2396  GED_ERROR) {
2397  edit_cmd_free(&subcmd);
2398  return GED_ERROR;
2399  }
2400  cur_arg->type |= EDIT_TARGET_OBJ;
2401  cur_arg = edit_arg_postfix_new(subcmd.cmd_line.args);
2402  }
2403 
2404  /* free unused arg block */
2406 
2407  if (edit_cmd_consolidate(gedp, &subcmd, 0) == GED_ERROR)
2408  return GED_ERROR;
2409  if (subcmd.cmd->add_cl_args(gedp, &subcmd, GED_ERROR) == GED_ERROR)
2410  return GED_ERROR;
2411  ret = edit(gedp, &subcmd);
2412  edit_cmd_free(&subcmd);
2413  return ret;
2414 
2415 err_missing_arg:
2416  bu_vls_printf(gedp->ged_result_str, "Missing argument for option -%c",
2417  bu_optopt);
2418  edit_cmd_free(&subcmd);
2419  return GED_ERROR;
2420 }
2421 
2422 
2423 /*
2424  * Local Variables:
2425  * tab-width: 8
2426  * mode: C
2427  * indent-tabs-mode: t
2428  * c-file-style: "stroustrup"
2429  * End:
2430  * ex: shiftwidth=4 tabstop=8
2431  */
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
add_cl_args_handler add_cl_args
Definition: edit.c:573
struct edit_arg **(* get_arg_head_handler)(const union edit_cmd *const cmd, int idx)
Definition: edit.c:561
#define EDIT_TARGET_OBJ_BATCH_TYPES
Definition: edit.c:496
struct edit_cmd::@20::@25 ref_factor
HIDDEN int edit_translate_add_cl_args(struct ged *gedp, union edit_cmd *const cmd, const int flags)
Definition: edit.c:1456
union tree * db_find_named_leaf(union tree *tp, const char *cp)
Definition: db_tree.c:393
size_t fp_len
Definition: db_fullpath.h:44
struct edit_cmd::@19 rotate
HIDDEN int edit_scale_wrapper(struct ged *gedp, const union edit_cmd *const cmd)
Definition: edit.c:1294
void db_dup_full_path(struct db_full_path *newp, const struct db_full_path *oldp)
Definition: db_fullpath.c:87
Definition: ged.h:338
HIDDEN int edit_str_to_arg(struct ged *gedp, const char *str, struct edit_arg *arg, const int flags)
Definition: edit.c:1762
struct db_i * dbip
Definition: raytrace.h:1266
Definition: clone.c:90
#define EDIT_COORD_Y
Definition: edit.c:463
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
HIDDEN void edit_cmd_sduplicate(union edit_cmd *const dest, const union edit_cmd *const src)
Definition: edit.c:997
HIDDEN void edit_arg_duplicate(struct edit_arg **dest, const struct edit_arg *src)
Definition: edit.c:667
#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
#define EDIT_USE_TARGETS
Definition: edit.c:490
HIDDEN void edit_cmd_free(union edit_cmd *const cmd)
Definition: edit.c:977
#define EDIT_CMD_ENABLE
Definition: edit.c:571
struct edit_cmd::@21::@26 ref_vector
struct rt_wdb * ged_wdbp
Definition: ged.h:340
char * bu_optarg
Definition: globals.c:91
HIDDEN struct edit_arg ** edit_translate_get_arg_head(const union edit_cmd *const cmd, int idx)
Definition: edit.c:1558
Header file for the BRL-CAD common definitions.
int bu_optind
Definition: globals.c:89
#define EDIT_ROTATE_ARG_HEADS_LEN
#define EDIT_MAX_ARG_OPTIONS
Definition: edit.c:441
char * help
Definition: edit.c:568
#define DB_FULL_PATH_CUR_DIR(_pp)
Definition: db_fullpath.h:51
#define RT_DIR_REGION
region
Definition: raytrace.h:885
struct edit_cmd::@18 cmd_line
#define BU_ASSERT(_equation)
Definition: defines.h:216
HIDDEN int edit(struct ged *gedp, union edit_cmd *const subcmd)
Definition: edit.c:1655
int bu_getopt(int nargc, char *const nargv[], const char *ostr)
Definition: getopt.c:43
void db_full_path_init(struct db_full_path *pathp)
Definition: db_fullpath.c:40
unsigned int type
Definition: edit.c:451
#define EDIT_ABS_POS
Definition: edit.c:486
#define GED_ERROR
Definition: ged.h:61
HIDDEN int edit_strs_to_arg(struct ged *gedp, int *argc, const char **argv[], struct edit_arg *arg, int flags)
Definition: edit.c:1912
#define HIDDEN
Definition: common.h:86
HIDDEN void edit_arg_duplicate_in_place(struct edit_arg *const dest, const struct edit_arg *src)
Definition: edit.c:636
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
#define EDIT_TO
Definition: edit.c:481
#define GED_DB_PUT_INTERNAL(_gedp, _dp, _intern, _resource, _flags)
Definition: ged.h:243
#define EDIT_CMD_DISABLE
Definition: edit.c:570
if(share_geom)
Definition: nmg_mod.c:3829
char * strchr(const char *sp, int c)
HIDDEN int edit_translate_wrapper(struct ged *gedp, const union edit_cmd *const cmd)
Definition: edit.c:1436
#define DB_FULL_PATH_GET(_pp, _i)
Definition: db_fullpath.h:55
HIDDEN struct edit_arg * edit_arg_postfix_new(struct edit_arg *head)
Definition: edit.c:619
char * usage
Definition: edit.c:567
void * memset(void *s, int c, size_t n)
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
#define EDIT_COORDS_ALL
Definition: edit.c:465
#define GED_CHECK_DATABASE_OPEN(_gedp, _flags)
Definition: ged.h:114
#define EDIT_COORD_X
Definition: edit.c:462
struct edit_cmd::@19::@23 ref_angle
#define EDIT_TRANSLATE_ARG_HEADS_LEN
#define RT_CK_DB_INTERNAL(_p)
Definition: raytrace.h:207
int bu_optopt
Definition: globals.c:90
#define BU_ALLOC(_ptr, _type)
Definition: malloc.h:223
HIDDEN int edit_arg_is_empty(struct edit_arg *arg)
Definition: edit.c:678
#define RT_DIR_SOLID
this name is a solid
Definition: raytrace.h:883
int db_string_to_path(struct db_full_path *pp, const struct db_i *dbip, const char *str)
Definition: db_fullpath.c:361
char cl_options[EDIT_MAX_ARG_OPTIONS]
Definition: edit.c:449
#define LOOKUP_QUIET
Definition: raytrace.h:893
HIDDEN int edit_rotate_wrapper(struct ged *gedp, const union edit_cmd *const cmd)
Definition: edit.c:1217
int _ged_get_solid_keypoint(struct ged *const gedp, fastf_t *const pt, const struct rt_db_internal *const ip, const fastf_t *const mat)
Definition: get_solid_kp.c:41
void bn_mat_inv(mat_t output, const mat_t input)
#define TREE_NULL
Definition: raytrace.h:1181
struct edit_arg * to
Definition: edit.c:520
struct edit_cmd::@20::@24 ref_scale
void db_free_full_path(struct db_full_path *pp)
Definition: db_fullpath.c:473
HIDDEN void edit_arg_postfix(struct edit_arg *head, struct edit_arg *node)
Definition: edit.c:602
struct edit_arg * next
Definition: edit.c:448
int(* exec_handler)(struct ged *gedp, const union edit_cmd *const cmd)
Definition: edit.c:558
#define GED_QUIET
Definition: ged.h:64
matp_t tl_mat
xform matp, NULL ==> identity
Definition: raytrace.h:1173
HIDDEN int edit_cmd_expand_vectors(struct ged *gedp, union edit_cmd *const subcmd)
Definition: edit.c:1028
#define EDIT_SCALE_ARG_HEADS_LEN
get_arg_head_handler get_arg_head
Definition: edit.c:574
struct edit_arg * args
Definition: edit.c:512
HIDDEN void edit_arg_init(struct edit_arg *arg)
Definition: edit.c:587
HIDDEN int edit_arg_expand_meta(struct ged *gedp, struct edit_arg *meta_arg, const struct edit_arg *src_objs, const int flags)
Definition: edit.c:904
char * opt_global
Definition: edit.c:566
HIDDEN int edit_cmd_consolidate(struct ged *gedp, union edit_cmd *const subcmd, int skip_common_objects)
Definition: edit.c:1102
int ged_get_obj_bounds(struct ged *gedp, int argc, const char *argv[], int use_air, point_t rpp_min, point_t rpp_max)
void bn_mat_mul(mat_t o, const mat_t a, const mat_t b)
unsigned int coords_used
Definition: edit.c:450
HIDDEN int edit_rotate(struct ged *gedp, const vect_t *axis_from, const vect_t *axis_to, const vect_t *center, const vect_t *angle_origin, const vect_t *angle_from, const vect_t *angle_to, const struct db_full_path *path)
Definition: edit.c:1195
struct edit_cmd::@17 common
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
#define EDIT_REL_DIST
Definition: edit.c:485
#define EDIT_NATURAL_ORIGIN
Definition: edit.c:489
const struct edit_cmd_tab * cmd
Definition: edit.c:503
HIDDEN int edit_scale_add_cl_args(struct ged *gedp, union edit_cmd *const cmd, const int flags)
Definition: edit.c:1311
#define EDIT_CMD_HELP
const struct edit_cmd_tab * padding_for_cmd
Definition: edit.c:506
int(* add_cl_args_handler)(struct ged *gedp, union edit_cmd *const cmd, const int flags)
Definition: edit.c:559
HIDDEN int edit_rotate_add_cl_args(struct ged *gedp, union edit_cmd *const cmd, const int flags)
Definition: edit.c:1235
HIDDEN struct edit_arg ** edit_rotate_get_arg_head(const union edit_cmd *const cmd, int idx)
Definition: edit.c:1250
HIDDEN struct edit_arg ** edit_scale_get_arg_head(const union edit_cmd *const cmd, int idx)
Definition: edit.c:1326
struct db_full_path * object
Definition: edit.c:452
HIDDEN int edit_arg_to_apparent_coord(struct ged *gedp, const struct edit_arg *const arg, vect_t *const coord)
Definition: edit.c:766
struct tree::tree_db_leaf tr_l
void * idb_ptr
Definition: raytrace.h:195
char * name
Definition: edit.c:565
#define EDIT_COORD_IS_SET_X
Definition: edit.c:471
mat_t gtd_xform
Definition: ged.h:1917
#define RT_DIR_COMB
combination
Definition: raytrace.h:884
#define BU_ASSERT_PTR(_lhs, _relation, _rhs)
Definition: defines.h:227
struct edit_arg * objects
Definition: edit.c:507
int bu_opterr
Definition: globals.c:88
struct edit_cmd::@19::@22 ref_axis
union tree * tree
Leading to tree_db_leaf leaves.
Definition: raytrace.h:938
int edit_scale(struct ged *gedp, const vect_t *scale_from, const vect_t *scale_to, const vect_t *center, const vect_t *factor_from, const vect_t *factor_to, const struct db_full_path *path)
Definition: edit.c:1273
Definition: edit.c:447
HIDDEN void edit_cmd_init(union edit_cmd *const subcmd)
Definition: edit.c:960
Definition: edit.c:502
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 EDIT_COORD_Z
Definition: edit.c:464
#define GED_HELP
Definition: ged.h:62
#define EDIT_TARGET_OBJ
Definition: edit.c:482
#define GED_DB_GET_INTERNAL(_gedp, _intern, _dp, _mat, _resource, _flags)
Definition: ged.h:233
#define EDIT_COORD_IS_SET_Z
Definition: edit.c:473
int enabled
Definition: edit.c:569
#define DB_FULL_PATH_ROOT_DIR(_pp)
Definition: db_fullpath.h:54
struct edit_arg * from
Definition: edit.c:519
HIDDEN void edit_arg_free(struct edit_arg *arg)
Definition: edit.c:713
int ged_path_validate(struct ged *gedp, const struct db_full_path *const path)
Definition: path.c:84
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
struct edit_cmd::@21 translate
double dbi_local2base
local2mm
Definition: raytrace.h:807
struct edit_cmd::@20 scale
HIDDEN void edit_arg_free_all(struct edit_arg *arg)
Definition: edit.c:742
vect_t * vector
Definition: edit.c:453
HIDDEN void edit_arg_free_last(struct edit_arg *arg)
Definition: edit.c:724
HIDDEN int edit_translate(struct ged *gedp, const vect_t *const from, const vect_t *const to, const struct db_full_path *const path)
Definition: edit.c:1348
#define GED_CHECK_READ_ONLY(_gedp, _flags)
Definition: ged.h:181
int d_flags
flags
Definition: raytrace.h:869
HIDDEN const point_t delta
Definition: sh_prj.c:618
double fastf_t
Definition: defines.h:300
exec_handler exec
Definition: edit.c:572
HIDDEN void edit_arg_free_inner(struct edit_arg *arg)
Definition: edit.c:695
struct edit_arg * origin
Definition: edit.c:524
void rt_db_free_internal(struct rt_db_internal *ip)
Definition: dir.c:216
#define EDIT_COORD_IS_SET_Y
Definition: edit.c:472
int _ged_get_obj_bounds2(struct ged *gedp, int argc, const char *argv[], struct _ged_trace_data *gtdp, point_t rpp_min, point_t rpp_max)
This version works if the last member of the path is a primitive.
int ged_edit(struct ged *gedp, int argc, const char *argv[])
Definition: edit.c:1965
struct edit_arg * center
Definition: edit.c:522
HIDDEN int edit_arg_to_coord(struct ged *gedp, struct edit_arg *const arg, vect_t *coord)
Definition: edit.c:861
#define EDIT_FROM
Definition: edit.c:480
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126