Revision: 45778
http://brlcad.svn.sourceforge.net/brlcad/?rev=45778&view=rev
Author: bhinesley
Date: 2011-08-03 23:28:47 +0000 (Wed, 03 Aug 2011)
Log Message:
-----------
Started on functions that convert db_full_path objects to points (natural
origin/bounding box center); WIP. edit() was getting a bit difficult to read,
which has led to several bugs, so I broke out batch expansion code into
edit_arg_expand(). There are still some problems preventing this from working,
but I haven't commited in a while and need to. Several changes to struct
edit_arg helper functions; needed more versatility
Modified Paths:
--------------
brlcad/trunk/src/libged/edit.c
Modified: brlcad/trunk/src/libged/edit.c
===================================================================
--- brlcad/trunk/src/libged/edit.c 2011-08-03 21:46:31 UTC (rev 45777)
+++ brlcad/trunk/src/libged/edit.c 2011-08-03 23:28:47 UTC (rev 45778)
@@ -811,21 +811,19 @@
};
/*
- * edit_arg flags of coordinates that will be used
+ * edit_arg coordinate flags
*/
+
+/* edit_arg flags of coordinates that will be used */
#define EDIT_COORD_X 0x01
#define EDIT_COORD_Y 0x02
#define EDIT_COORD_Z 0x04
-#define EDIT_COORDS_ALL (EDIT_COORD_X + EDIT_COORD_Y + EDIT_COORD_Z)
+#define EDIT_COORDS_ALL (EDIT_COORD_X | EDIT_COORD_Y | EDIT_COORD_Z)
-/*
- * edit_arg flags of coordinates that are already set
- */
+/* edit_arg flags of coordinates that are already set */
#define EDIT_COORD_IS_SET_X 0x08
#define EDIT_COORD_IS_SET_Y 0x10
#define EDIT_COORD_IS_SET_Z 0x20
-#define EDIT_COORDS_ALL_ARE_SET (EDIT_COORD_IS_SET_X, EDIT_COORD_IS_SET_Y, \
- EDIT_COORD_IS_SET_Z)
/*
* edit_arg argument type flags
@@ -844,9 +842,10 @@
#define EDIT_NATURAL_ORIGIN 0x20 /* use n.o. of object */
#define EDIT_USE_TARGETS 0x40 /* for batch ops */
-/*
- * when performing batch operations, these flags are not discarded
- * from the target object*/
+/* all type modifier flags that indicate the arg contains an obj */
+#define EDIT_OBJ_TYPE_MODS (EDIT_NATURAL_ORIGIN | EDIT_USE_TARGETS)
+
+/* in batch ops, these flags are not discarded from the target obj */
#define EDIT_TARGET_OBJ_BATCH_TYPES (EDIT_NATURAL_ORIGIN)
@@ -978,6 +977,53 @@
}
/**
+ * Duplicate an argument node on top of an existing node. Prior to
+ * calling, caller is responsible for freeing objects contained by
+ * destination argument node, if necessary, via edit_arg_free_inner().
+ */
+HIDDEN void
+edit_arg_duplicate_in_place(struct edit_arg *const dest,
+ const struct edit_arg *src)
+{
+ int i;
+
+ edit_arg_init(dest);
+ dest->next = (struct edit_arg *)NULL;
+ for (i = 0; i < EDIT_MAX_ARG_OPTIONS; ++i)
+ dest->cl_options[i] = src->cl_options[i];
+ dest->coords_used = src->coords_used;
+ dest->type = src->type;
+ if (dest->object) {
+ dest->object = (struct db_full_path *)bu_malloc(
+ sizeof(struct db_full_path),
+ "struct db_full_path block for"
+ "edit_arg_duplicate_in_place()");
+ db_full_path_init(dest->object);
+ db_dup_full_path(dest->object, src->object);
+ }
+ if (src->vector) {
+ dest->vector = (vect_t *)bu_malloc(sizeof(vect_t),
+ "vect_t block for edit_arg_duplicate_in_place()");
+ *dest->vector[0] = *src->vector[0];
+ *dest->vector[1] = *src->vector[1];
+ *dest->vector[2] = *src->vector[2];
+ }
+}
+
+/**
+ * Duplicate an argument node into a new argument. Caller is
+ * responsible for freeing destination argument, if necessary,
+ * using the appropriate edit_arg_free*() function.
+ */
+HIDDEN void
+edit_arg_duplicate(struct edit_arg **dest, const struct edit_arg *src)
+{
+ *dest = (struct edit_arg *)bu_malloc(sizeof(struct edit_arg),
+ "edit_arg block for edit_arg_duplicate()");
+ edit_arg_duplicate_in_place(*dest, src);
+}
+
+/**
* Returns GED_OK if arg is empty, otherwise GED_ERROR is returned
*/
HIDDEN int
@@ -994,17 +1040,29 @@
}
/**
- * Free an argument node.
+ * Free all objects containd by an argument node.
*/
HIDDEN void
-edit_arg_free(struct edit_arg *arg)
+edit_arg_free_inner(struct edit_arg *arg)
{
if (arg->object) {
db_free_full_path(arg->object);
bu_free((genptr_t)arg->object, "db_string_to_path");
+ arg->object = NULL;
}
- if (arg->vector)
+ if (arg->vector) {
bu_free(arg->vector, "vect_t");
+ arg->vector = NULL;
+ }
+}
+
+/**
+ * Free an argument node, including what it contains.
+ */
+HIDDEN void
+edit_arg_free(struct edit_arg *arg)
+{
+ edit_arg_free_inner(arg);
bu_free(arg, "edit_arg");
}
@@ -1110,7 +1168,7 @@
/**
* Initialize command argument-pointer members to NULL.
*/
-HIDDEN void
+void
edit_rotate_init(union edit_cmd *const subcmd)
{
subcmd->rotate.objects =
@@ -1173,6 +1231,12 @@
static int idx = -1;
struct edit_arg *arg_heads[EDIT_ROTATE_ARG_HEADS_LEN];
+ if (!cmd) {
+ /* (re)initialize */
+ idx = -1;
+ return (struct edit_arg *) NULL;
+ }
+
arg_heads[0] = cmd->rotate.objects;
arg_heads[1] = cmd->rotate.ref_axis.from;
arg_heads[2] = cmd->rotate.ref_axis.to;
@@ -1206,7 +1270,7 @@
/**
* Initialize command argument-pointer members to NULL.
*/
-HIDDEN void
+void
edit_scale_init(union edit_cmd *const subcmd)
{
subcmd->scale.objects =
@@ -1258,6 +1322,11 @@
static int idx = -1;
struct edit_arg *arg_heads[EDIT_SCALE_ARG_HEADS_LEN];
+ if (!cmd) {
+ /* (re)initialize */
+ idx = -1;
+ return (struct edit_arg *) NULL;
+ }
arg_heads[0] = cmd->scale.objects;
arg_heads[1] = cmd->scale.ref_scale.from;
@@ -1333,7 +1402,8 @@
BU_ASSERT_PTR(cur_arg->next, !=, NULL);
/* a 'from' position is set; only flags that were possible
- * when this function was last updated should be handled */
+ * when this function was last updated should be handled
+ */
BU_ASSERT(cur_arg->type ^ ~(EDIT_FROM |
EDIT_NATURAL_ORIGIN |
EDIT_USE_TARGETS));
@@ -1349,11 +1419,13 @@
if ((cur_arg->type & EDIT_TO) || (cur_arg->type == 0)) {
/* if there isn't an EDIT_TARGET_OBJECT, this func shouldn't
- * be called */
+ * be called
+ */
BU_ASSERT_PTR(cur_arg->next, !=, NULL);
/* a 'TO' position is set; only flags that were possible when
- * this function was last updated should be handled */
+ * this function was last updated should be handled
+ */
BU_ASSERT(cur_arg->type ^ ~(EDIT_TO |
EDIT_NATURAL_ORIGIN |
EDIT_REL_DIST |
@@ -1401,7 +1473,8 @@
return GED_ERROR;
} else {
/* a target obj is set; only flags that were possible when
- * this function was last updated should be handled */
+ * this function was last updated should be handled
+ */
BU_ASSERT(cur_arg->type ^ ~(EDIT_TARGET_OBJ |
EDIT_NATURAL_ORIGIN));
}
@@ -1411,6 +1484,14 @@
goto err_option_unknown;
} while ((cur_arg = cur_arg->next));
+ /* the default 'FROM' is the first target object */
+ if (!cmd->translate.ref_vector.from) {
+ edit_arg_duplicate(&cmd->translate.ref_vector.from,
+ cmd->translate.objects);
+ cmd->translate.ref_vector.from->next = NULL;
+ cmd->translate.ref_vector.from->type ^= EDIT_TARGET_OBJ | EDIT_FROM;
+ }
+
return GED_OK;
err_option_unknown:
@@ -1426,6 +1507,12 @@
#define EDIT_TRANSLATE_ARG_HEADS_LEN 3
struct edit_arg *arg_heads[EDIT_TRANSLATE_ARG_HEADS_LEN];
static int idx = -1;
+
+ if (!cmd) {
+ /* (re)initialize */
+ idx = -1;
+ return (struct edit_arg *) NULL;
+ }
arg_heads[0] = cmd->translate.objects;
arg_heads[1] = cmd->translate.ref_vector.from;
@@ -1487,17 +1574,132 @@
*/
-#if 0
-int
-edit_obj_to_coord(struct edit_arg *arg) {
+enum edit_obj_point_types {
+ DEFAULT = 0,
+ BB_CENTER = DEFAULT,
+ NATURAL_ORIGIN
+};
+
+/*
+ * Returns the coordinates of a particular point on an object.
+ */
+vect_t *
+edit_path_to_coord(struct db_full_path *obj_path,
+ enum edit_obj_point_types point_type)
+{
+ struct directory *obj = NULL;
+ struct directory *path = NULL;
+
+ if (obj_path->fp_len == 1)
+ obj = obj_path->fp_names[0];
+ else {
+ BU_ASSERT(obj_path->fp_len == 2); /* "dir/object" only */
+ /* FIXME: obj/path flags need to be checked earlier!!! */
+ BU_ASSERT(path->d_flags & (RT_DIR_REGION | RT_DIR_COMB));
+ path = obj_path->fp_names[0];
+ obj = obj_path->fp_names[1];
+ }
+ /* FIXME: obj/path flags need to be checked earlier!!! */
+ BU_ASSERT(obj->d_flags & (RT_DIR_SOLID | RT_DIR_REGION | RT_DIR_COMB))
+
+ /* TODO: get matrix modified coordinates of object */
+ switch (point_type) {
+ case NATURAL_ORIGIN:
+ break;
+ case BB_CENTER:
+ default:
+ break;
+ }
+
return GED_OK;
}
-int
-edit_obj_offset_to_coord(struct edit_arg *arg) {
- /* edit_obj_to_coord(arg) + offsets */
+
+/**
+ * Converts edit_arg objects+offsets to coordinates, and removes
+ * objects. Only respects object argument type modifier flags.
+ */
+void
+edit_arg_obj_path_to_coord(struct edit_arg *const arg)
+{
+ vect_t *obj_coord;
+
+ if (arg->type & EDIT_NATURAL_ORIGIN) {
+ obj_coord = edit_path_to_coord(arg->object, NATURAL_ORIGIN);
+ arg->type &= ~EDIT_NATURAL_ORIGIN;
+ } else
+ obj_coord = edit_path_to_coord(arg->object, DEFAULT);
+
+ if (arg->vector) {
+ VADD2(*arg->vector, *arg->vector, *obj_coord);
+ bu_free((genptr_t)obj_coord, "vect_t");
+ } else
+ arg->vector = obj_coord;
+
+ /* unhandled object argument type modifier flags */
+ BU_ASSERT(!(arg->type & EDIT_OBJ_TYPE_MODS))
+
+ db_free_full_path(arg->object);
+ bu_free((genptr_t)arg->object, "db_full_path");
+ arg->object = (struct db_full_path *)NULL;
+}
+
+/**
+ * "Expands" object arguments for a batch operation.
+ *
+ * meta_arg is replaced a list of copies of src_objects, with
+ * certain meta_arg flags applied and/or consolidated with those of
+ * the source objects. Objects + offsets are converted to coordinates.
+ *
+ * Set GED_QUIET or GED_ERROR bits in 'flags' to suppress or enable
+ * output to ged_result_str, respectively.
+ *
+ * Returns GED_ERROR on failure, and GED_OK on success.
+ */
+HIDDEN int
+edit_arg_expand(struct ged *gedp, struct edit_arg *meta_arg,
+ const struct edit_arg *src_objs, const int flags)
+{
+ struct edit_arg *prototype;
+ struct edit_arg *dest;
+ const struct edit_arg *src;
+ const int noisy = (flags & GED_ERROR); /* side with verbosity */
+ int firstrun = 1;
+
+ BU_ASSERT(!meta_arg->next); /* should be at end of list */
+
+ /* repurpose meta_arg, so ptr-to-ptr isn't required */
+ edit_arg_duplicate(&prototype, meta_arg);
+ edit_arg_free_inner(meta_arg);
+ edit_arg_init(meta_arg);
+ dest = meta_arg;
+
+ for (src = src_objs; src; src = src->next, dest = dest->next) {
+ if (firstrun) {
+ firstrun = 0;
+ src = src_objs;
+ edit_arg_duplicate_in_place(dest, src);
+ }
+ else
+ edit_arg_duplicate(&dest, src);
+
+ /* never use coords that target obj didn't include */
+ dest->coords_used &= prototype->coords_used;
+ if (!dest->coords_used) {
+ if (noisy)
+ bu_vls_printf(gedp->ged_result_str,
+ "coordinate filters for batch operator and target"
+ "objects result in no coordinates being used");
+ return GED_ERROR;
+ }
+
+ /* respect certain type flags from the prototype/target obj */
+ dest->type &= EDIT_TARGET_OBJ_BATCH_TYPES;
+ dest->type |= prototype->type & EDIT_TARGET_OBJ_BATCH_TYPES;
+
+ edit_arg_obj_path_to_coord(dest);
+ }
return GED_OK;
}
-#endif
/**
* A wrapper for the edit commands. It adds the capability to perform
@@ -1507,7 +1709,7 @@
* commands.
*
* Set GED_QUIET or GED_ERROR bits in 'flags' to suppress or enable
- * output to ged_result_str, respectively.
+ * output to ged_result_str, respectively.
*
* Returns GED_ERROR on failure, and GED_OK on success.
*
@@ -1523,86 +1725,39 @@
{
struct edit_arg *arg_head;
struct edit_arg *cur_arg;
- struct edit_arg *dest_arg;
- int noisy = (flags & GED_ERROR); /* side with verbosity */
+ const int noisy = (flags & GED_ERROR); /* side with verbosity */
- arg_head = subcmd->cmd->get_next_arg_head(subcmd);
- /* TODO: do all processing of subcmd->common.objects first, so
- * that they are not done again once the batch arguments are
- * expanded (targets copied) */
-#if 0
- /* no target objects should have vectors only */
- BU_ASSERT(cur_arg->object || !dest_arg->vector);
+ /* initialize */
+ (void)subcmd->cmd->get_next_arg_head((union edit_cmd *)NULL);
- /* cmd line opts should have been handled/removed */
- BU_ASSERT(cur_arg->cl_options[0] == '\0');
-#endif
-
- /* done with objects */
+ /* check all arg nodes in subcmd->common.objects first; they may
+ * be copied later if there are any batch modifiers to expand.
+ */
arg_head = subcmd->cmd->get_next_arg_head(subcmd);
+ for (cur_arg = arg_head; cur_arg; cur_arg = cur_arg->next) {
+ /* target objects must be... objects */
+ BU_ASSERT(cur_arg->object);
- do {
- if (arg_head->type & EDIT_USE_TARGETS) {
- dest_arg = arg_head;
+ /* cmd line opts should have been handled/removed */
+ BU_ASSERT(cur_arg->cl_options[0] == '\0');
+ }
- /* expand batch operator */
- for (cur_arg = subcmd->common.objects; cur_arg;
- cur_arg = cur_arg->next) {
+ /* process all other arg nodes */
+ while ((arg_head = subcmd->cmd->get_next_arg_head(subcmd)) !=
+ subcmd->common.objects) {
- /* copy target object to batch argument; freed when cmd is */
- dest_arg->next = (struct edit_arg *)bu_malloc(
- sizeof(struct edit_arg),
- "edit_arg block for edit()");
- dest_arg = dest_arg->next;
- edit_arg_init(dest_arg);
+ for (cur_arg = arg_head; cur_arg; cur_arg = cur_arg->next) {
- dest_arg->next = NULL;
- dest_arg->cl_options[0] = '\0';
-
- /* never use coords that target obj didn't include */
- dest_arg->coords_used &= arg_head->coords_used;
- if (!dest_arg->coords_used) {
- if (noisy)
- bu_vls_printf(gedp->ged_result_str,
- "coordinate filters for batch"
- " operator and target objects result in"
- " no coordinates being used");
- return GED_ERROR;
- }
-
- /* respect certain flags from the target object */
- dest_arg->type |= (arg_head->type &
- EDIT_TARGET_OBJ_BATCH_TYPES);
-
- if (cur_arg->object) {
- dest_arg->object = (struct db_full_path *)bu_malloc(
- sizeof(struct db_full_path),
- "db_full_path block for edit()");
- db_full_path_init(dest_arg->object);
- db_dup_full_path(dest_arg->object, cur_arg->object);
- }
- if (cur_arg->vector) {
- cur_arg->vector = (vect_t *)bu_malloc(
- sizeof(vect_t),
- "vect_t block for edit()");
- *dest_arg->vector[0] = *cur_arg->vector[0];
- *dest_arg->vector[1] = *cur_arg->vector[1];
- *dest_arg->vector[2] = *cur_arg->vector[2];
- }
- }
- arg_head = subcmd->cmd->get_next_arg_head(subcmd);
- continue;
- }
-
- for (cur_arg = arg_head; cur_arg; cur_arg = cur_arg->next) {
/* cmd line opts should have been handled/removed */
BU_ASSERT(cur_arg->cl_options[0] == '\0');
- /* TODO: convert objects + offsets to coords */
+ if (cur_arg->type & EDIT_USE_TARGETS)
+ edit_arg_expand(gedp, cur_arg, subcmd->common.objects,
+ (noisy ? GED_ERROR : GED_OK));
+ else if (cur_arg->object)
+ edit_arg_obj_path_to_coord(cur_arg);
}
- arg_head = subcmd->cmd->get_next_arg_head(subcmd);
- } while (arg_head != subcmd->common.objects);
-
+ }
return GED_OK;
}
@@ -1611,7 +1766,7 @@
* for examples of acceptable argument strings.
*
* Set GED_QUIET or GED_ERROR bits in 'flags' to suppress or enable
- * output to ged_result_str, respectively.
+ * output to ged_result_str, respectively.
*
* Returns GED_ERROR on failure, and GED_OK on success.
*/
@@ -1636,8 +1791,7 @@
if (!arg->object && !(arg->type & EDIT_USE_TARGETS)) {
- /* identical batch operators; objs with the same name are
- * masked */
+ /* same batch operators; objs with same name are masked */
if (BU_STR_EQUAL(str, ".") || BU_STR_EQUAL(str, "--")) {
arg->type |= EDIT_USE_TARGETS;
return GED_OK;
@@ -1676,7 +1830,8 @@
/* FIXME: this conditional should be replaced by adding
* inner slash stripping to db_string_to_path (which is
* used below), and using a simple check for fp_len > 2
- * here */
+ * here
+ */
if (noisy)
bu_vls_printf(gedp->ged_result_str, "invalid path, \"%s\"\n"
"It is only meaningful to have one or two "
@@ -1705,7 +1860,8 @@
/* if either all coordinates are being set or an object has been
* set, then attempt to intepret/record the number as the next
- * unset X, Y, or Z Z coordinate/position */
+ * unset X, Y, or Z Z coordinate/position
+ */
if ((arg->coords_used & EDIT_COORDS_ALL) || arg->object) {
if (!arg->vector) {
arg->vector = (vect_t *)bu_malloc(sizeof(vect_t),
@@ -1777,9 +1933,9 @@
* arguments. See subcommand manuals for examples of acceptable
* argument strings.
*
- * Set GED_QUIET or GED_ERROR bits in flags to suppress or enable
- * output to ged_result_str, respectively. Note that output is always
- * suppressed after the first string.
+ * Set GED_QUIET or GED_ERROR bits in 'flags' to suppress or enable
+ * output to ged_result_str, respectively. Note that output is
+ * always suppressed after the first string.
*
* Returns GED_OK if at least one string is converted, otherwise
* GED_ERROR is returned.
@@ -1857,7 +2013,8 @@
* translate' rather than just 'translate'. Also, the help option
* of subcommands is not displayed properly; it should display
* when command is called directly, i.e. 'translate', but not
- * 'edit translate' */
+ * 'edit translate'
+ */
for (i = 0; edit_cmds[i].name; ++i) {
/* search for command name in the table */
@@ -1958,7 +2115,8 @@
* the help system with an object that happened to be
* named "help" than the other way around. This syntax is
* needed to access the help system when a subcmd is the
- * calling command. */
+ * calling command.
+ */
if (argc == 1 &&
BU_STR_EQUAL(edit_cmds[EDIT_CMD_HELP].name,
argv[0])) {
@@ -2015,8 +2173,10 @@
/* no options are required by default*/
while (edit_strs_to_arg(gedp, &argc, &argv, cur_arg, GED_QUIET) !=
GED_ERROR) {
if (argc == 0) {
- if (edit_arg_is_empty(subcmd.cmd_line.args))
+ if (edit_arg_is_empty(subcmd.cmd_line.args)) {
edit_arg_free(subcmd.cmd_line.args);
+ subcmd.cmd_line.args = NULL;
+ }
cur_arg = subcmd.cmd_line.args;
if (cur_arg->next) {
@@ -2025,7 +2185,8 @@
}
/* parsing is done and there were no options, so all args
- * after the first arg should be a target obj */
+ * after the first arg should be a target obj
+ */
for (; cur_arg; cur_arg = cur_arg->next) {
if (!(cur_arg->object)) {
bu_vls_printf(gedp->ged_result_str,
@@ -2049,7 +2210,8 @@
/* All leading args are parsed. If we're not not at an option,
* then there is a bad arg. Let the conversion function cry about
- * what it choked on */
+ * what it choked on
+ */
if (strlen(argv[0]) > 1 && ((*argv)[0] != '-') && isdigit((*argv)[1])) {
ret = edit_strs_to_arg(gedp, &argc, &argv, cur_arg, GED_ERROR);
edit_cmd_free(&subcmd);
@@ -2136,7 +2298,8 @@
/* set flags for standard options. it's more readible to just
* switch on c again than the alternative: to add several
- * checks and/or goto's */
+ * checks and/or goto's
+ */
switch (c) {
case 'x':
cur_arg->coords_used |= EDIT_COORD_X;
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
BlackBerry® DevCon Americas, Oct. 18-20, San Francisco, CA
The must-attend event for mobile developers. Connect with experts.
Get tools for creating Super Apps. See the latest technologies.
Sessions, hands-on labs, demos & much more. Register early & save!
http://p.sf.net/sfu/rim-blackberry-1
_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits