Compare commits

...
3 Commits
Author SHA1 Message Date
Clifford Yapp 2923050080 Preserve primitive edits across failed saves and restores
A failed checkpoint could discard the last saved state, and a
failed revert could discard the current primitive. Restoring
selected pipe or NMG geometry could also leave stale handles.

Stage exports and imports before replacing live state, clear
selections and refresh the keypoint after restore, and preserve
SPH and REC types. Consume rejected edit input so a later command
cannot reuse it, and prevent view-update counts from accumulating.

Cover failed saves and restores, repeated revert, selected geometry,
and default and non-default database units.
2026-09-24 14:25:53 -04:00
Clifford Yapp 9dd4023aa5 Prevent rejected primitive edits from changing geometry
Rejected height moves in TGC, CLINE, and EXTRUDE could replace
valid geometry; NMG edge moves could partly change faces while
reporting success. BOT edge splits could leave unused vertices, and
malformed parameter text could partly overwrite seven primitives.

Stage edits before applying them. Reject invalid REC and uniform
scale inputs without changing geometry, and report scale failures.
Cover these paths in default and non-default units, including CRLF
parameter text and NMG selection remapping.
2026-09-24 14:25:53 -04:00
Clifford Yapp d39ca30602 Prevent rejected ARB edits from corrupting geometry
Mouse face drags and several ARB edit helpers could change points or
planes before detecting invalid geometry. Subsequent edits then began
from inconsistent state and could produce unexpected shape changes.

Validate candidate geometry before committing it, restore state on
rejected edits, and cover repeated mouse drags with non-default units.
2026-09-24 14:25:53 -04:00
30 changed files with 956 additions and 665 deletions
+6 -4
View File
@@ -510,7 +510,9 @@ rt_knob_edit_sca(
int matrix_edit);
/* Equivalent to sedit - run editing logic after input data is set in
* rt_edit container. Returns BRLCAD_ERROR if the primitive edit fails. */
* rt_edit container. Transient input flags are consumed whether the edit
* succeeds or fails; parameter values remain available to the caller.
* Returns BRLCAD_ERROR if the primitive edit fails. */
RT_EXPORT extern int
rt_edit_process(struct rt_edit *s);
@@ -532,7 +534,7 @@ rt_edit_snap_point(point2d_t pt, const struct rt_edit *s);
* restored later with rt_edit_revert().
*
* The snapshot is stored inside the rt_edit struct. Calling this
* function again overwrites any previous snapshot (single-level undo).
* function again replaces the previous snapshot only on success.
*
* @return BRLCAD_OK on success, BRLCAD_ERROR if the export failed.
*/
@@ -543,8 +545,8 @@ rt_edit_checkpoint(struct rt_edit *s);
* Restore primitive parameters from the snapshot saved by
* rt_edit_checkpoint().
*
* If no snapshot has been saved (or the last snapshot was already
* consumed) this function logs a message and returns BRLCAD_ERROR.
* The snapshot remains available for repeated restores. If none has
* been saved, this function logs a message and returns BRLCAD_ERROR.
*
* @return BRLCAD_OK on success, BRLCAD_ERROR otherwise.
*/
+61 -23
View File
@@ -1107,6 +1107,14 @@ rt_knob_edit_sca(struct rt_edit *s, int matrix_edit)
}
}
static void
rt_edit_clear_input(struct rt_edit *s)
{
s->e_inpara = 0;
s->e_mvalid = 0;
s->es_scale = 0.0;
}
/*
* A great deal of magic takes place here, to accomplish solid editing.
*
@@ -1122,7 +1130,20 @@ rt_edit_process(struct rt_edit *s)
bu_clbk_t f = NULL;
void *d = NULL;
++s->update_views;
if (!s)
return BRLCAD_ERROR;
const int type = s->es_int.idb_type;
if (type <= ID_NULL || type > ID_MAX_SOLID ||
!s->es_int.idb_ptr || EDOBJ[type].magic != RT_FUNCTAB_MAGIC) {
bu_vls_printf(s->log_str, "rt_edit_process: no editable solid\n");
rt_edit_clear_input(s);
return BRLCAD_ERROR;
}
const int prior_update_views = s->update_views;
if (!s->update_views)
s->update_views = 1;
int had_method = 0;
const struct rt_db_internal *ip = &s->es_int;
@@ -1134,6 +1155,8 @@ rt_edit_process(struct rt_edit *s)
if (f)
(*f)(0, NULL, d, NULL);
}
s->update_views = prior_update_views;
rt_edit_clear_input(s);
return BRLCAD_ERROR;
}
if (bu_vls_strlen(s->log_str)) {
@@ -1149,7 +1172,7 @@ rt_edit_process(struct rt_edit *s)
case RT_EDIT_IDLE:
/* do nothing more */
--s->update_views;
s->update_views = prior_update_views;
break;
default:
{
@@ -1166,6 +1189,8 @@ rt_edit_process(struct rt_edit *s)
rt_edit_map_clbk_get(&f, &d, s->m, ECMD_PRINT_RESULTS, BU_CLBK_DURING);
if (f)
(*f)(0, NULL, d, NULL);
s->update_views = prior_update_views;
rt_edit_clear_input(s);
return BRLCAD_ERROR;
}
}
@@ -1196,9 +1221,7 @@ rt_edit_process(struct rt_edit *s)
}
// Inputs processed, reset
s->e_inpara = 0;
s->e_mvalid = 0;
s->es_scale = 0.0;
rt_edit_clear_input(s);
return BRLCAD_OK;
}
@@ -1221,15 +1244,15 @@ rt_edit_checkpoint(struct rt_edit *s)
RT_CK_DB_INTERNAL(&s->es_int);
/* Release any previous snapshot */
bu_free_external(&s->es_ckpt);
BU_EXTERNAL_INIT(&s->es_ckpt);
if (rt_obj_export(&s->es_ckpt, &s->es_int, 1.0, s->dbip) < 0) {
struct bu_external candidate = BU_EXTERNAL_INIT_ZERO;
if (rt_obj_export(&candidate, &s->es_int, 1.0, s->dbip) < 0) {
bu_free_external(&candidate);
bu_vls_printf(s->log_str, "rt_edit_checkpoint: export failed\n");
return BRLCAD_ERROR;
}
bu_free_external(&s->es_ckpt);
s->es_ckpt = candidate;
return BRLCAD_OK;
}
@@ -1245,26 +1268,41 @@ rt_edit_revert(struct rt_edit *s)
return BRLCAD_ERROR;
}
int type = s->es_int.idb_type;
/* Release current contents */
rt_db_free_internal(&s->es_int);
RT_DB_INTERNAL_INIT(&s->es_int);
/* rt_obj_import dispatches on ip->idb_minor_type, which RT_DB_INTERNAL_INIT
* resets to -1. Restore the saved type so the right ft_importN is called. */
s->es_int.idb_minor_type = type;
const int type = s->es_int.idb_type;
if (type <= ID_NULL || type > ID_MAX_SOLID || !s->es_int.idb_ptr) {
bu_vls_printf(s->log_str, "rt_edit_revert: no editable solid\n");
return BRLCAD_ERROR;
}
struct rt_db_internal restored;
RT_DB_INTERNAL_INIT(&restored);
restored.idb_minor_type = type;
mat_t identity;
MAT_IDN(identity);
if (rt_obj_import(&s->es_int, &s->es_ckpt, identity, s->dbip) < 0) {
int import_result = rt_obj_import(&restored, &s->es_ckpt, identity, s->dbip);
/* SPH and REC import through the ELL and TGC internal formats. */
bool compatible_type = restored.idb_type == type ||
(type == ID_SPH && restored.idb_type == ID_ELL) ||
(type == ID_REC && restored.idb_type == ID_TGC);
if (import_result < 0 || !compatible_type || !restored.idb_ptr) {
rt_db_free_internal(&restored);
bu_vls_printf(s->log_str, "rt_edit_revert: import failed\n");
return BRLCAD_ERROR;
}
/* If the type changed for some reason (shouldn't happen), keep the original */
if (s->es_int.idb_type != type)
s->es_int.idb_type = type;
restored.idb_type = type;
restored.idb_meth = &OBJ[type];
if (s->ipe_ptr && EDOBJ[type].ft_prim_edit_reset)
(*EDOBJ[type].ft_prim_edit_reset)(s);
rt_db_free_internal(&s->es_int);
s->es_int = restored;
rt_edit_clear_input(s);
s->acc_sc_sol = 1.0;
if (!s->e_keyfixed) {
s->e_keytag = "";
rt_get_solid_keypoint(s, &s->e_keypoint, &s->e_keytag, s->e_mat);
}
return BRLCAD_OK;
}
+9 -9
View File
@@ -3277,26 +3277,23 @@ int
rt_arb_calc_points(struct rt_arb_internal *arb, int cgtype, const plane_t planes[6], const struct bn_tol *tol)
{
int i;
point_t pt[8];
struct rt_arb_internal candidate;
RT_ARB_CK_MAGIC(arb);
candidate = *arb;
/* find new points for entire solid */
for (i = 0; i < 8; i++) {
if (rt_arb_3face_intersect(pt[i], planes, cgtype, i*3) < 0) {
if (rt_arb_3face_intersect(candidate.pt[i], planes, cgtype, i*3) < 0) {
bu_log("rt_arb_calc_points: Intersection of planes fails %d\n", i);
return -1; /* FAIL */
}
}
/* Move new points to arb tol->dist))*/
for (i = 0; i < 8; i++) {
VMOVE(arb->pt[i], pt[i]);
}
if (rt_arb_check_points(arb, cgtype, tol) < 0)
if (rt_arb_check_points(&candidate, cgtype, tol) < 0)
return -1;
memcpy(arb->pt, candidate.pt, sizeof(arb->pt));
return 0; /* success */
}
@@ -3397,6 +3394,7 @@ rt_arb_calc_planes(struct bu_vls *error_msg_ret,
const struct bn_tol *tol)
{
const int arb_faces[5][24] = rt_arb_faces;
plane_t candidate[6];
/* ARB4 at location 0, ARB5 at 1, etc. */
int type = cgtype - ARB4;
@@ -3405,6 +3403,7 @@ rt_arb_calc_planes(struct bu_vls *error_msg_ret,
RT_ARB_CK_MAGIC(arb);
BN_CK_TOL(tol);
memcpy(candidate, planes, sizeof(candidate));
for (int i = 0; i < 6; i++) {
if (arb_faces[type][i*4] == -1)
@@ -3414,7 +3413,7 @@ rt_arb_calc_planes(struct bu_vls *error_msg_ret,
int p2 = arb_faces[type][i*4+1];
int p3 = arb_faces[type][i*4+2];
if (bg_make_plane_3pnts(planes[i],
if (bg_make_plane_3pnts(candidate[i],
arb->pt[p1],
arb->pt[p2],
arb->pt[p3],
@@ -3425,6 +3424,7 @@ rt_arb_calc_planes(struct bu_vls *error_msg_ret,
}
}
memcpy(planes, candidate, sizeof(candidate));
return 0;
}
+106 -60
View File
@@ -1169,6 +1169,17 @@ rt_arb_edit(struct bu_vls *error_msg_ret,
return 1;
}
/* Intersections and plane updates can fail after changing several points. */
struct rt_arb_internal *original_arb = arb;
plane_t *original_planes = planes;
struct rt_arb_internal candidate = *arb;
plane_t candidate_planes[6];
vect_t edit_position;
memcpy(candidate_planes, planes, sizeof(candidate_planes));
VMOVE(edit_position, pos_model);
arb = &candidate;
planes = candidate_planes;
/* set the pointer */
switch (arb_type) {
case ARB4:
@@ -1246,7 +1257,7 @@ rt_arb_edit(struct bu_vls *error_msg_ret,
/* do the arb editing */
if (edit_class == RT_ARB_EDIT_POINT) {
/* moving a point - not an edge */
VMOVE(arb->pt[edit_type], pos_model);
VMOVE(arb->pt[edit_type], edit_position);
edptr += 4;
} else if (edit_class == RT_ARB_EDIT_EDGE) {
vect_t edge_dir;
@@ -1256,8 +1267,8 @@ rt_arb_edit(struct bu_vls *error_msg_ret,
pt2 = *edptr++;
if (flags & RT_ARB_EDIT_EDGE_DIR) {
VMOVE(edge_dir, pos_model);
VMOVE(pos_model, arb->pt[pt1]);
VMOVE(edge_dir, edit_position);
VMOVE(edit_position, arb->pt[pt1]);
} else {
/* calculate edge direction */
VSUB2(edge_dir, arb->pt[pt2], arb->pt[pt1]);
@@ -1271,7 +1282,7 @@ rt_arb_edit(struct bu_vls *error_msg_ret,
bp2 = *edptr++;
/* move the edge */
if (rt_arb_move_edge(error_msg_ret, arb, pos_model, bp1, bp2, pt1, pt2,
if (rt_arb_move_edge(error_msg_ret, arb, edit_position, bp1, bp2, pt1, pt2,
edge_dir, planes, tol))
goto err;
}
@@ -1377,6 +1388,8 @@ rt_arb_edit(struct bu_vls *error_msg_ret,
goto err;
}
memcpy(original_arb->pt, candidate.pt, sizeof(candidate.pt));
memcpy(original_planes, candidate_planes, sizeof(candidate_planes));
return 0; /* OK */
err:
@@ -1501,6 +1514,48 @@ edarb_canonicalize(struct rt_edit *s, struct rt_arb_internal *arb)
return BRLCAD_OK;
}
static int
arb_move_face_to_point(struct rt_edit *s, const point_t target)
{
struct rt_arb8_edit *a = (struct rt_arb8_edit *)s->ipe_ptr;
struct rt_arb_internal *arb = (struct rt_arb_internal *)s->es_int.idb_ptr;
struct rt_arb_internal candidate;
plane_t planes[6];
struct bu_vls error_msg = BU_VLS_INIT_ZERO;
int arb_type;
RT_ARB_CK_MAGIC(arb);
if (a->edit_menu < 0 || a->edit_menu >= ARB8_FACE_COUNT) {
bu_vls_printf(s->log_str, "Invalid ARB face index %d\n", a->edit_menu);
return BRLCAD_ERROR;
}
candidate = *arb;
memcpy(planes, a->es_peqn, sizeof(planes));
planes[a->edit_menu][W] = VDOT(planes[a->edit_menu], target);
arb_type = rt_arb_edit_type(s->log_str, s, arb, 0, s->tol);
if (!arb_type)
return BRLCAD_ERROR;
if (rt_arb_calc_points(&candidate, arb_type, (const plane_t *)planes, s->tol)) {
bu_vls_printf(s->log_str, "Cannot calculate ARB points\n");
return BRLCAD_ERROR;
}
if (edarb_canonicalize(s, &candidate) != BRLCAD_OK)
return BRLCAD_ERROR;
if (rt_arb_calc_planes(&error_msg, &candidate, arb_type, planes, s->tol)) {
bu_vls_printf(s->log_str, "%s", bu_vls_cstr(&error_msg));
bu_vls_free(&error_msg);
return BRLCAD_ERROR;
}
bu_vls_free(&error_msg);
memcpy(arb->pt, candidate.pt, sizeof(arb->pt));
memcpy(a->es_peqn, planes, sizeof(planes));
return BRLCAD_OK;
}
static int
arb_numeric_target(point_t target, struct rt_edit *s, int *edit_menu)
{
@@ -1535,38 +1590,13 @@ ecmd_arb_move_face(struct rt_edit *s)
{
struct rt_arb8_edit *a = (struct rt_arb8_edit *)s->ipe_ptr;
/* move face through definite point */
if (s->e_inpara) {
if (!s->e_inpara)
return BRLCAD_OK;
vect_t work;
if (arb_numeric_target(work, s, &a->edit_menu) != BRLCAD_OK)
return BRLCAD_ERROR;
if (a->edit_menu < 0 || a->edit_menu >= ARB8_FACE_COUNT) {
bu_vls_printf(s->log_str, "Invalid ARB face index %d\n", a->edit_menu);
return BRLCAD_ERROR;
}
struct rt_arb_internal *arb = (struct rt_arb_internal *)s->es_int.idb_ptr;
RT_ARB_CK_MAGIC(arb);
/* change D of planar equation */
a->es_peqn[a->edit_menu][W]=VDOT(&a->es_peqn[a->edit_menu][0], work);
/* find new vertices, put in record in vector notation */
int arb_type = rt_arb_edit_type(s->log_str, s, arb, 0, s->tol);
if (arb_type == 0)
return BRLCAD_ERROR;
if (rt_arb_calc_points(arb, arb_type, (const plane_t *)a->es_peqn, s->tol)) {
bu_vls_printf(s->log_str, "Cannot calculate ARB8 points\n");
return BRLCAD_ERROR;
}
if (edarb_canonicalize(s, arb) != BRLCAD_OK)
return BRLCAD_ERROR;
}
return 0;
point_t target;
if (arb_numeric_target(target, s, &a->edit_menu) != BRLCAD_OK)
return BRLCAD_ERROR;
return arb_move_face_to_point(s, target);
}
void
@@ -1757,11 +1787,16 @@ ecmd_arb_rotate_face(struct rt_edit *s)
if (arb_type == 0)
return BRLCAD_ERROR;
(void)rt_arb_calc_points(arb, arb_type, (const plane_t *)a->es_peqn, s->tol);
if (rt_arb_calc_points(arb, arb_type, (const plane_t *)a->es_peqn, s->tol)) {
bu_vls_printf(s->log_str, "Cannot calculate ARB points\n");
return BRLCAD_ERROR;
}
if (edarb_canonicalize(s, arb) != BRLCAD_OK) {
return BRLCAD_ERROR;
}
if (rt_arb_calc_planes(s->log_str, arb, arb_type, a->es_peqn, s->tol))
return BRLCAD_ERROR;
MAT_IDN(s->incr_change);
s->e_inpara = 0;
@@ -1850,7 +1885,6 @@ arb_mouse_move_element(struct rt_edit *s, const vect_t mousevec)
static int
edarb_move_face_mousevec(struct rt_edit *s, const vect_t mousevec)
{
struct rt_arb8_edit *a = (struct rt_arb8_edit *)s->ipe_ptr;
vect_t pos_view = VINIT_ZERO; /* Unrotated view space pos */
vect_t temp = VINIT_ZERO;
vect_t pos_model = VINIT_ZERO; /* Rotated screen space pos */
@@ -1859,24 +1893,7 @@ edarb_move_face_mousevec(struct rt_edit *s, const vect_t mousevec)
pos_view[Y] = mousevec[Y];
MAT4X3PNT(temp, s->vp->gv_view2model, pos_view);
MAT4X3PNT(pos_model, s->e_invmat, temp);
if (a->edit_menu < 0 || a->edit_menu >= ARB8_FACE_COUNT) {
bu_vls_printf(s->log_str, "Invalid ARB face index %d\n", a->edit_menu);
return BRLCAD_ERROR;
}
/* change D of planar equation */
a->es_peqn[a->edit_menu][W]=VDOT(&a->es_peqn[a->edit_menu][0], pos_model);
struct rt_arb_internal *arb =
(struct rt_arb_internal *)s->es_int.idb_ptr;
RT_ARB_CK_MAGIC(arb);
int arb_type = rt_arb_edit_type(s->log_str, s, arb, 0, s->tol);
if (arb_type == 0)
return BRLCAD_ERROR;
if (rt_arb_calc_points(arb, arb_type, (const plane_t *)a->es_peqn, s->tol)) {
bu_vls_printf(s->log_str, "Cannot calculate ARB8 points\n");
return BRLCAD_ERROR;
}
if (edarb_canonicalize(s, arb) != BRLCAD_OK)
if (arb_move_face_to_point(s, pos_model) != BRLCAD_OK)
return BRLCAD_ERROR;
edit_abs_tra(s, pos_view);
return BRLCAD_OK;
@@ -1889,6 +1906,9 @@ rt_edit_arb_edit(struct rt_edit *s)
struct rt_arb_internal *arb = (struct rt_arb_internal *)s->es_int.idb_ptr;
struct rt_arb8_edit *a = (struct rt_arb8_edit *)s->ipe_ptr;
RT_ARB_CK_MAGIC(arb);
struct rt_arb_internal original_arb = *arb;
plane_t original_planes[6];
memcpy(original_planes, a->es_peqn, sizeof(original_planes));
int ret = 0;
int arb_type = rt_arb_edit_type(s->log_str, s, arb, 0, s->tol);
@@ -1928,11 +1948,27 @@ rt_edit_arb_edit(struct rt_edit *s)
ecmd_arb_setup_rotface(s);
break;
case ECMD_ARB_ROTATE_FACE:
{
mat_t original_acc_rot, original_model_changes, original_incr_change;
int original_menu = a->edit_menu;
int original_fixv = a->fixv;
MAT_COPY(original_acc_rot, s->acc_rot_sol);
MAT_COPY(original_model_changes, s->model_changes);
MAT_COPY(original_incr_change, s->incr_change);
ret = ecmd_arb_rotate_face(s);
if (ret)
if (ret) {
memcpy(arb->pt, original_arb.pt, sizeof(arb->pt));
memcpy(a->es_peqn, original_planes, sizeof(original_planes));
MAT_COPY(s->acc_rot_sol, original_acc_rot);
MAT_COPY(s->model_changes, original_model_changes);
MAT_COPY(s->incr_change, original_incr_change);
a->edit_menu = original_menu;
a->fixv = original_fixv;
return ret;
}
/* The plane is current; bypass arb_planecalc below. */
return BRLCAD_OK;
}
case PTARB: /* move an ARB point */
case EARB: /* edit an ARB edge */
return edit_arb_element(s);
@@ -1942,19 +1978,29 @@ rt_edit_arb_edit(struct rt_edit *s)
arb_planecalc:
if (ret != BRLCAD_OK)
goto arb_failed;
if (edarb_canonicalize(s, arb) != BRLCAD_OK) {
return BRLCAD_ERROR;
goto arb_failed;
}
/* must re-calculate the face plane equations for arbs */
arb_type = rt_arb_edit_type(s->log_str, s, arb, 0, s->tol);
if (arb_type == 0)
return BRLCAD_ERROR;
if (rt_arb_calc_planes(&error_msg, arb, arb_type, a->es_peqn, s->tol) < 0)
goto arb_failed;
if (rt_arb_calc_planes(&error_msg, arb, arb_type, a->es_peqn, s->tol) < 0) {
bu_vls_printf(s->log_str, "%s", bu_vls_cstr(&error_msg));
bu_vls_free(&error_msg);
goto arb_failed;
}
bu_vls_free(&error_msg);
return ret;
arb_failed:
memcpy(arb->pt, original_arb.pt, sizeof(arb->pt));
memcpy(a->es_peqn, original_planes, sizeof(original_planes));
return BRLCAD_ERROR;
}
C_DECL int
+29 -14
View File
@@ -608,6 +608,21 @@ ecmd_bot_movev_list(struct rt_edit *s)
* triangles that share the new vertex.
* No e_para needed.
*/
static int
bot_face_edge_other(const int *face, int v0, int v1)
{
if ((face[0] == v0 && face[1] == v1) ||
(face[0] == v1 && face[1] == v0))
return face[2];
if ((face[1] == v0 && face[2] == v1) ||
(face[1] == v1 && face[2] == v0))
return face[0];
if ((face[2] == v0 && face[0] == v1) ||
(face[2] == v1 && face[0] == v0))
return face[1];
return -1;
}
static int
ecmd_bot_esplit(struct rt_edit *s)
{
@@ -618,13 +633,25 @@ ecmd_bot_esplit(struct rt_edit *s)
int v0 = b->bot_verts[0];
int v1 = b->bot_verts[1];
if (v0 < 0 || v1 < 0 || b->bot_verts[2] >= 0) {
if (v0 < 0 || v1 < 0 || v0 == v1 ||
(size_t)v0 >= bot->num_vertices || (size_t)v1 >= bot->num_vertices ||
b->bot_verts[2] >= 0) {
bu_vls_printf(s->log_str,
"ERROR: ECMD_BOT_ESPLIT requires a single edge selection "
"(ECMD_BOT_PICKE first)\n");
return BRLCAD_ERROR;
}
size_t incident_faces = 0;
for (size_t fi = 0; fi < bot->num_faces; fi++) {
if (bot_face_edge_other(&bot->faces[fi * 3], v0, v1) >= 0)
incident_faces++;
}
if (!incident_faces) {
bu_vls_printf(s->log_str, "ERROR: selected BOT edge was not found\n");
return BRLCAD_ERROR;
}
/* Compute midpoint */
point_t mid;
VADD2SCALE(mid, &bot->vertices[v0*3], &bot->vertices[v1*3], 0.5);
@@ -642,19 +669,7 @@ ecmd_bot_esplit(struct rt_edit *s)
(size_t *)bu_malloc(orig_nf * sizeof(size_t), "split BOT face parents") :
NULL;
for (size_t fi = 0; fi < orig_nf; fi++) {
int f0 = bot->faces[fi*3];
int f1 = bot->faces[fi*3+1];
int f2 = bot->faces[fi*3+2];
/* Check whether this face contains the directed or reverse edge */
int other = -1;
if ((f0 == v0 && f1 == v1) || (f0 == v1 && f1 == v0)) {
other = f2;
} else if ((f1 == v0 && f2 == v1) || (f1 == v1 && f2 == v0)) {
other = f0;
} else if ((f2 == v0 && f0 == v1) || (f2 == v1 && f0 == v0)) {
other = f1;
}
int other = bot_face_edge_other(&bot->faces[fi * 3], v0, v1);
if (other < 0)
continue; /* edge not in this face */
+14 -11
View File
@@ -174,7 +174,7 @@ cline_scale(struct rt_edit *s)
int
ecmd_cline_move_h(struct rt_edit *s)
{
vect_t work;
vect_t work, height;
point_t model_point;
struct rt_cline_internal *cli =
(struct rt_cline_internal *)s->es_int.idb_ptr;
@@ -182,6 +182,7 @@ ecmd_cline_move_h(struct rt_edit *s)
void *d = NULL;
RT_CLINE_CK_MAGIC(cli);
VMOVE(height, cli->h);
if (s->e_inpara) {
if (s->e_inpara != 3) {
@@ -194,24 +195,22 @@ ecmd_cline_move_h(struct rt_edit *s)
if (s->mv_context) {
MAT4X3PNT(work, s->e_invmat, model_point);
VSUB2(cli->h, work, cli->v);
VSUB2(height, work, cli->v);
} else
VSUB2(cli->h, model_point, cli->v);
VSUB2(height, model_point, cli->v);
}
/* check for zero H vector */
if (MAGNITUDE(cli->h) <= SQRT_SMALL_FASTF) {
bu_vls_printf(s->log_str, "Zero H vector not allowed, resetting to +Z\n");
if (edit_validate_height(s, height) != BRLCAD_OK) {
rt_edit_map_clbk_get(&f, &d, s->m, ECMD_PRINT_RESULTS, BU_CLBK_DURING);
if (f)
(*f)(0, NULL, d, NULL);
VSET(cli->h, 0.0, 0.0, 1.0);
return BRLCAD_ERROR;
}
VMOVE(cli->h, height);
return 0;
}
void
static int
ecmd_cline_move_h_mousevec(struct rt_edit *s, const vect_t mousevec)
{
vect_t pos_view = VINIT_ZERO; /* Unrotated view space pos */
@@ -228,8 +227,13 @@ ecmd_cline_move_h_mousevec(struct rt_edit *s, const vect_t mousevec)
/* Do NOT change pos_view[Z] ! */
MAT4X3PNT(temp, s->vp->gv_view2model, pos_view);
MAT4X3PNT(tr_temp, s->e_invmat, temp);
VSUB2(cli->h, tr_temp, cli->v);
vect_t height;
VSUB2(height, tr_temp, cli->v);
if (edit_validate_height(s, height) != BRLCAD_OK)
return BRLCAD_ERROR;
VMOVE(cli->h, height);
edit_abs_tra(s, pos_view);
return BRLCAD_OK;
}
C_DECL int
@@ -279,8 +283,7 @@ rt_edit_cline_edit_xy(
edit_stra_xy(&pos_view, s, mousevec);
break;
case ECMD_CLINE_MOVE_H:
ecmd_cline_move_h_mousevec(s, mousevec);
return BRLCAD_OK;
return ecmd_cline_move_h_mousevec(s, mousevec);
default:
return edit_generic_xy(s, mousevec);
}
+65 -9
View File
@@ -114,6 +114,35 @@ edit_param_read_scalar(fastf_t *out, char **cursor, const char *label,
return isfinite(*out) ? BRLCAD_OK : BRLCAD_ERROR;
}
int
edit_param_read_fields(const char *input, const struct edit_param_field *fields,
size_t field_count)
{
if (!input || !fields || !field_count)
return BRLCAD_ERROR;
char *buffer = bu_strdup(input);
char *cursor = buffer;
int result = BRLCAD_OK;
for (size_t i = 0; i < field_count; i++) {
const struct edit_param_field *field = &fields[i];
if (field->count == ELEMENTS_PER_VECT)
result = edit_param_read_vector(field->value, &cursor,
field->label, field->conversion);
else if (field->count == 1)
result = edit_param_read_scalar(field->value, &cursor,
field->label, field->conversion);
else
result = BRLCAD_ERROR;
if (result != BRLCAD_OK)
break;
}
if (result == BRLCAD_OK && edit_param_next_line(&cursor))
result = BRLCAD_ERROR;
bu_free(buffer, "primitive parameter text");
return result;
}
int
edit_repair_parse_options(struct bu_vls *log_str, int argc,
const char **argv, const struct bu_opt_desc *options)
@@ -194,6 +223,7 @@ edit_sscale(struct rt_edit *s)
{
mat_t mat, mat1, scalemat;
struct rt_db_internal *ip = &s->es_int;
fastf_t scale = s->es_scale;
if (s->e_inpara > 1) {
bu_vls_printf(s->log_str, "ERROR: only one argument needed\n");
@@ -202,23 +232,37 @@ edit_sscale(struct rt_edit *s)
}
if (s->e_inpara) {
/* accumulate the scale factor */
s->es_scale = s->e_para[0] / s->acc_sc_sol;
s->acc_sc_sol = s->e_para[0];
if (!isfinite(s->e_para[0]) || s->e_para[0] <= 0.0 ||
!isfinite(s->acc_sc_sol) || s->acc_sc_sol <= 0.0) {
bu_vls_printf(s->log_str, "ERROR: scale must be finite and positive\n");
return BRLCAD_ERROR;
}
scale = s->e_para[0] / s->acc_sc_sol;
}
/* No pending scale operation — nothing to apply. */
if (!s->e_inpara && s->es_scale < SMALL_FASTF)
if (!s->e_inpara && ZERO(scale))
return 0;
bn_mat_scale_about_pnt(scalemat, s->e_keypoint, s->es_scale);
if (!isfinite(scale) || scale <= 0.0 ||
!OBJ[ip->idb_type].ft_mat ||
bn_mat_scale_about_pnt(scalemat, s->e_keypoint, scale)) {
bu_vls_printf(s->log_str, "ERROR: cannot apply solid scale\n");
return BRLCAD_ERROR;
}
bn_mat_mul(mat1, scalemat, s->e_mat);
bn_mat_mul(mat, s->e_invmat, mat1);
if (OBJ[ip->idb_type].ft_mat)
(*OBJ[ip->idb_type].ft_mat)(ip, mat, ip);
if ((*OBJ[ip->idb_type].ft_mat)(ip, mat, ip)) {
bu_vls_printf(s->log_str, "ERROR: solid scale failed\n");
return BRLCAD_ERROR;
}
/* reset solid scale factor */
s->es_scale = 1.0;
if (s->e_inpara)
s->acc_sc_sol = s->e_para[0];
return 0;
}
@@ -312,6 +356,19 @@ edit_scale_equal_axes(struct rt_edit *s, vect_t a, vect_t b, vect_t c)
return BRLCAD_OK;
}
int
edit_validate_height(struct rt_edit *s, const vect_t height)
{
fastf_t length = MAGNITUDE(height);
fastf_t min_length = s->tol ? fmax(s->tol->dist, SQRT_SMALL_FASTF) :
SQRT_SMALL_FASTF;
if (!isfinite(length) || length <= min_length) {
bu_vls_printf(s->log_str, "Zero or invalid H vector not allowed\n");
return BRLCAD_ERROR;
}
return BRLCAD_OK;
}
void
edit_stra(struct rt_edit *s)
{
@@ -467,8 +524,7 @@ edit_generic(
switch (s->edit_flag) {
case RT_PARAMS_EDIT_SCALE:
/* scale the solid uniformly about its vertex point */
edit_sscale(s);
return BRLCAD_OK;
return edit_sscale(s);
case RT_PARAMS_EDIT_TRANS:
/* translate solid */
edit_stra(s);
+15
View File
@@ -67,6 +67,10 @@ edit_scale_length(struct rt_edit *s, vect_t *axis, fastf_t *scalar);
int
edit_scale_equal_axes(struct rt_edit *s, vect_t a, vect_t b, vect_t c);
/* Reject height endpoint edits that would collapse the primitive. */
int
edit_validate_height(struct rt_edit *s, const vect_t height);
/* Validate dimension counts before converting numeric edit parameters. */
int
edit_parse_sample_count(uint32_t *count, fastf_t value);
@@ -95,6 +99,17 @@ int
edit_param_read_scalar(fastf_t *out, char **cursor, const char *label,
fastf_t local2base);
struct edit_param_field {
const char *label;
fastf_t *value;
int count;
fastf_t conversion;
};
int
edit_param_read_fields(const char *text, const struct edit_param_field *fields,
size_t field_count);
/* translate solid */
void
edit_stra(struct rt_edit *s);
+13 -75
View File
@@ -223,16 +223,6 @@ rt_edit_ehy_write_params(
bu_vls_printf(p, "Dist to asymptotes: %.9f\n", ehy->ehy_c * base2local);
}
#define read_params_line_incr \
lc = (ln) ? (ln + lcj) : NULL; \
if (!lc) { \
bu_free(wc, "wc"); \
return BRLCAD_ERROR; \
} \
ln = strchr(lc, tc); \
if (ln) *ln = '\0'; \
while (lc && strchr(lc, ':')) lc++
C_DECL int
rt_edit_ehy_read_params(
struct rt_db_internal *ip,
@@ -241,74 +231,22 @@ rt_edit_ehy_read_params(
fastf_t local2base
)
{
double a = 0.0;
double b = 0.0;
double c = 0.0;
struct rt_ehy_internal *ehy = (struct rt_ehy_internal *)ip->idb_ptr;
RT_EHY_CK_MAGIC(ehy);
if (!fc)
struct rt_ehy_internal candidate = *ehy;
const struct edit_param_field fields[] = {
{"Vertex", candidate.ehy_V, ELEMENTS_PER_VECT, local2base},
{"Height", candidate.ehy_H, ELEMENTS_PER_VECT, local2base},
{"Semi-major axis", candidate.ehy_Au, ELEMENTS_PER_VECT, 1.0},
{"Semi-major length", &candidate.ehy_r1, 1, local2base},
{"Semi-minor length", &candidate.ehy_r2, 1, local2base},
{"Dist to asymptotes", &candidate.ehy_c, 1, local2base}
};
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK ||
ZERO(MAGNITUDE(candidate.ehy_Au)))
return BRLCAD_ERROR;
// We're getting the file contents as a string, so we need to split it up
// to process lines. See https://stackoverflow.com/a/17983619
// Figure out if we need to deal with Windows line endings
const char *crpos = strchr(fc, '\r');
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
char tc = (crlf) ? '\r' : '\n';
// If we're CRLF jump ahead another character.
int lcj = (crlf) ? 2 : 1;
char *ln = NULL;
char *wc = bu_strdup(fc);
char *lc = wc;
// Set up initial line
ln = strchr(lc, tc);
if (ln) *ln = '\0';
// Trim off prefixes, if user left them in
while (lc && strchr(lc, ':')) lc++;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(ehy->ehy_V, a, b, c);
VSCALE(ehy->ehy_V, ehy->ehy_V, local2base);
// Set up Height line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(ehy->ehy_H, a, b, c);
VSCALE(ehy->ehy_H, ehy->ehy_H, local2base);
// Set up Semi-major axis line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(ehy->ehy_Au, a, b, c);
VUNITIZE(ehy->ehy_Au);
// Set up Semi-major length line
read_params_line_incr;
sscanf(lc, "%lf", &a);
ehy->ehy_r1 = a * local2base;
// Set up Semi-minor length line
read_params_line_incr;
sscanf(lc, "%lf", &a);
ehy->ehy_r2 = a * local2base;
// Set up distance to asymptotes line
read_params_line_incr;
sscanf(lc, "%lf", &a);
ehy->ehy_c = a * local2base;
// Cleanup
bu_free(wc, "wc");
VUNITIZE(candidate.ehy_Au);
*ehy = candidate;
return BRLCAD_OK;
}
+12 -69
View File
@@ -196,16 +196,6 @@ rt_edit_epa_write_params(
bu_vls_printf(p, "Semi-minor length: %.9f\n", epa->epa_r2 * base2local);
}
#define read_params_line_incr \
lc = (ln) ? (ln + lcj) : NULL; \
if (!lc) { \
bu_free(wc, "wc"); \
return BRLCAD_ERROR; \
} \
ln = strchr(lc, tc); \
if (ln) *ln = '\0'; \
while (lc && strchr(lc, ':')) lc++
C_DECL int
rt_edit_epa_read_params(
struct rt_db_internal *ip,
@@ -214,68 +204,21 @@ rt_edit_epa_read_params(
fastf_t local2base
)
{
double a = 0.0;
double b = 0.0;
double c = 0.0;
struct rt_epa_internal *epa = (struct rt_epa_internal *)ip->idb_ptr;
RT_EPA_CK_MAGIC(epa);
if (!fc)
struct rt_epa_internal candidate = *epa;
const struct edit_param_field fields[] = {
{"Vertex", candidate.epa_V, ELEMENTS_PER_VECT, local2base},
{"Height", candidate.epa_H, ELEMENTS_PER_VECT, local2base},
{"Semi-major axis", candidate.epa_Au, ELEMENTS_PER_VECT, 1.0},
{"Semi-major length", &candidate.epa_r1, 1, local2base},
{"Semi-minor length", &candidate.epa_r2, 1, local2base}
};
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK ||
ZERO(MAGNITUDE(candidate.epa_Au)))
return BRLCAD_ERROR;
// We're getting the file contents as a string, so we need to split it up
// to process lines. See https://stackoverflow.com/a/17983619
// Figure out if we need to deal with Windows line endings
const char *crpos = strchr(fc, '\r');
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
char tc = (crlf) ? '\r' : '\n';
// If we're CRLF jump ahead another character.
int lcj = (crlf) ? 2 : 1;
char *ln = NULL;
char *wc = bu_strdup(fc);
char *lc = wc;
// Set up initial line (Vertex)
ln = strchr(lc, tc);
if (ln) *ln = '\0';
// Trim off prefixes, if user left them in
while (lc && strchr(lc, ':')) lc++;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(epa->epa_V, a, b, c);
VSCALE(epa->epa_V, epa->epa_V, local2base);
// Set up Height line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(epa->epa_H, a, b, c);
VSCALE(epa->epa_H, epa->epa_H, local2base);
// Set up Semi-major axis line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(epa->epa_Au, a, b, c);
VUNITIZE(epa->epa_Au);
// Set up Semi-major length line
read_params_line_incr;
sscanf(lc, "%lf", &a);
epa->epa_r1 = a * local2base;
// Set up Semi-minor length line
read_params_line_incr;
sscanf(lc, "%lf", &a);
epa->epa_r2 = a * local2base;
// Cleanup
bu_free(wc, "wc");
VUNITIZE(candidate.epa_Au);
*epa = candidate;
return BRLCAD_OK;
}
+12 -69
View File
@@ -148,16 +148,6 @@ rt_edit_eto_write_params(
bu_vls_printf(p, "Radius of rotation: %.9f\n", eto->eto_r * base2local);
}
#define read_params_line_incr \
lc = (ln) ? (ln + lcj) : NULL; \
if (!lc) { \
bu_free(wc, "wc"); \
return BRLCAD_ERROR; \
} \
ln = strchr(lc, tc); \
if (ln) *ln = '\0'; \
while (lc && strchr(lc, ':')) lc++
C_DECL int
rt_edit_eto_read_params(
struct rt_db_internal *ip,
@@ -166,68 +156,21 @@ rt_edit_eto_read_params(
fastf_t local2base
)
{
double a = 0.0;
double b = 0.0;
double c = 0.0;
struct rt_eto_internal *eto = (struct rt_eto_internal *)ip->idb_ptr;
RT_ETO_CK_MAGIC(eto);
if (!fc)
struct rt_eto_internal candidate = *eto;
const struct edit_param_field fields[] = {
{"Vertex", candidate.eto_V, ELEMENTS_PER_VECT, local2base},
{"Normal", candidate.eto_N, ELEMENTS_PER_VECT, 1.0},
{"Semi-major axis", candidate.eto_C, ELEMENTS_PER_VECT, local2base},
{"Semi-minor length", &candidate.eto_rd, 1, local2base},
{"Radius of rotation", &candidate.eto_r, 1, local2base}
};
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK ||
ZERO(MAGNITUDE(candidate.eto_N)))
return BRLCAD_ERROR;
// We're getting the file contents as a string, so we need to split it up
// to process lines. See https://stackoverflow.com/a/17983619
// Figure out if we need to deal with Windows line endings
const char *crpos = strchr(fc, '\r');
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
char tc = (crlf) ? '\r' : '\n';
// If we're CRLF jump ahead another character.
int lcj = (crlf) ? 2 : 1;
char *ln = NULL;
char *wc = bu_strdup(fc);
char *lc = wc;
// Set up initial line (Vertex)
ln = strchr(lc, tc);
if (ln) *ln = '\0';
// Trim off prefixes, if user left them in
while (lc && strchr(lc, ':')) lc++;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(eto->eto_V, a, b, c);
VSCALE(eto->eto_V, eto->eto_V, local2base);
// Set up Normal line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(eto->eto_N, a, b, c);
VUNITIZE(eto->eto_N);
// Set up Semi-major axis line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(eto->eto_C, a, b, c);
VSCALE(eto->eto_C, eto->eto_C, local2base);
// Set up Semi-minor length line
read_params_line_incr;
sscanf(lc, "%lf", &a);
eto->eto_rd = a * local2base;
// Set up Radius of rotation line
read_params_line_incr;
sscanf(lc, "%lf", &a);
eto->eto_r = a * local2base;
// Cleanup
bu_free(wc, "wc");
VUNITIZE(candidate.eto_N);
*eto = candidate;
return BRLCAD_OK;
}
+14 -11
View File
@@ -248,7 +248,7 @@ ecmd_extr_skt_name(struct rt_edit *s)
int
ecmd_extr_mov_h(struct rt_edit *s)
{
vect_t work;
vect_t work, height;
point_t model_point;
struct rt_extrude_internal *extr =
(struct rt_extrude_internal *)s->es_int.idb_ptr;
@@ -256,6 +256,7 @@ ecmd_extr_mov_h(struct rt_edit *s)
void *d = NULL;
RT_EXTRUDE_CK_MAGIC(extr);
VMOVE(height, extr->h);
if (s->e_inpara) {
if (s->e_inpara != 3) {
bu_vls_printf(s->log_str, "ERROR: three arguments needed\n");
@@ -268,22 +269,20 @@ ecmd_extr_mov_h(struct rt_edit *s)
if (s->mv_context) {
/* apply s->e_invmat to convert to real model coordinates */
MAT4X3PNT(work, s->e_invmat, model_point);
VSUB2(extr->h, work, extr->V);
VSUB2(height, work, extr->V);
} else {
VSUB2(extr->h, model_point, extr->V);
VSUB2(height, model_point, extr->V);
}
}
/* check for zero H vector */
if (MAGNITUDE(extr->h) <= SQRT_SMALL_FASTF) {
bu_vls_printf(s->log_str, "Zero H vector not allowed, resetting to +Z\n");
if (edit_validate_height(s, height) != BRLCAD_OK) {
rt_edit_map_clbk_get(&f, &d, s->m, ECMD_PRINT_RESULTS, BU_CLBK_DURING);
if (f)
(*f)(0, NULL, d, NULL);
VSET(extr->h, 0.0, 0.0, 1.0);
return BRLCAD_ERROR;
}
VMOVE(extr->h, height);
return 0;
}
@@ -380,7 +379,7 @@ ecmd_extr_rot_h(struct rt_edit *s)
}
/* Use mouse to change location of point V+H */
void
static int
ecmd_extr_mov_h_mousevec(struct rt_edit *s, const vect_t mousevec)
{
vect_t pos_view = VINIT_ZERO; /* Unrotated view space pos */
@@ -396,8 +395,13 @@ ecmd_extr_mov_h_mousevec(struct rt_edit *s, const vect_t mousevec)
/* Do NOT change pos_view[Z] ! */
MAT4X3PNT(temp, s->vp->gv_view2model, pos_view);
MAT4X3PNT(tr_temp, s->e_invmat, temp);
VSUB2(extr->h, tr_temp, extr->V);
vect_t height;
VSUB2(height, tr_temp, extr->V);
if (edit_validate_height(s, height) != BRLCAD_OK)
return BRLCAD_ERROR;
VMOVE(extr->h, height);
edit_abs_tra(s, pos_view);
return BRLCAD_OK;
}
@@ -558,8 +562,7 @@ rt_edit_extrude_edit_xy(
edit_stra_xy(&pos_view, s, mousevec);
break;
case ECMD_EXTR_MOV_H:
ecmd_extr_mov_h_mousevec(s, mousevec);
return BRLCAD_OK;
return ecmd_extr_mov_h_mousevec(s, mousevec);
default:
return edit_generic_xy(s, mousevec);
}
+10 -69
View File
@@ -155,16 +155,6 @@ rt_edit_hyp_write_params(
bu_vls_printf(p, "Ratio of Neck to Base: %.9f\n", hyp->hyp_bnr);
}
#define read_params_line_incr \
lc = (ln) ? (ln + lcj) : NULL; \
if (!lc) { \
bu_free(wc, "wc"); \
return BRLCAD_ERROR; \
} \
ln = strchr(lc, tc); \
if (ln) *ln = '\0'; \
while (lc && strchr(lc, ':')) lc++
C_DECL int
rt_edit_hyp_read_params(
struct rt_db_internal *ip,
@@ -173,68 +163,19 @@ rt_edit_hyp_read_params(
fastf_t local2base
)
{
double a = 0.0;
double b = 0.0;
double c = 0.0;
struct rt_hyp_internal *hyp = (struct rt_hyp_internal *)ip->idb_ptr;
RT_HYP_CK_MAGIC(hyp);
if (!fc)
struct rt_hyp_internal candidate = *hyp;
const struct edit_param_field fields[] = {
{"Vertex", candidate.hyp_Vi, ELEMENTS_PER_VECT, local2base},
{"Height", candidate.hyp_Hi, ELEMENTS_PER_VECT, local2base},
{"Semi-major axis", candidate.hyp_A, ELEMENTS_PER_VECT, local2base},
{"Semi-minor length", &candidate.hyp_b, 1, local2base},
{"Ratio of Neck to Base", &candidate.hyp_bnr, 1, 1.0}
};
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK)
return BRLCAD_ERROR;
// We're getting the file contents as a string, so we need to split it up
// to process lines. See https://stackoverflow.com/a/17983619
// Figure out if we need to deal with Windows line endings
const char *crpos = strchr(fc, '\r');
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
char tc = (crlf) ? '\r' : '\n';
// If we're CRLF jump ahead another character.
int lcj = (crlf) ? 2 : 1;
char *ln = NULL;
char *wc = bu_strdup(fc);
char *lc = wc;
// Set up initial line (Vertex)
ln = strchr(lc, tc);
if (ln) *ln = '\0';
// Trim off prefixes, if user left them in
while (lc && strchr(lc, ':')) lc++;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(hyp->hyp_Vi, a, b, c);
VSCALE(hyp->hyp_Vi, hyp->hyp_Vi, local2base);
// Set up Height line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(hyp->hyp_Hi, a, b, c);
VSCALE(hyp->hyp_Hi, hyp->hyp_Hi, local2base);
// Set up Semi-major axis line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(hyp->hyp_A, a, b, c);
VSCALE(hyp->hyp_A, hyp->hyp_A, local2base);
// Set up Semi-minor length line
read_params_line_incr;
sscanf(lc, "%lf", &a);
hyp->hyp_b = a * local2base;
// Set up Ratio of Neck to Base line
read_params_line_incr;
sscanf(lc, "%lf", &a);
hyp->hyp_bnr = a;
// Cleanup
bu_free(wc, "wc");
*hyp = candidate;
return BRLCAD_OK;
}
+47 -1
View File
@@ -676,6 +676,52 @@ nmg_edit_target_point(point_t target, const struct rt_edit *s, const point_t loc
VMOVE(target, base_point);
}
static int
nmg_edit_move_edge(struct rt_edit *s, const point_t new_pt)
{
struct rt_nmg_edit *n = (struct rt_nmg_edit *)s->ipe_ptr;
struct model *original = (struct model *)s->es_int.idb_ptr;
struct model *candidate;
struct nmg_struct_counts counts;
uint32_t **candidate_structs;
struct edgeuse *candidate_eu;
int result;
if (nmg_find_model(&n->es_eu->l.magic) != original)
return 1;
/* A wire move cannot fail after it starts changing geometry. */
if (!nmg_find_fu_of_eu(n->es_eu))
return nmg_move_edge_thru_pnt(n->es_eu, new_pt, s->tol);
candidate = nmg_clone_model(original);
if (!candidate)
return 1;
candidate_structs = nmg_m_struct_count(&counts, candidate);
candidate_eu = (struct edgeuse *)candidate_structs[n->es_eu->index];
NMG_CK_EDGEUSE(candidate_eu);
result = nmg_move_edge_thru_pnt(candidate_eu, new_pt, s->tol);
if (result) {
bu_free(candidate_structs, "NMG candidate structures");
nmg_km(candidate);
return result;
}
/* Clone indices identify the corresponding selections in the new model. */
n->es_eu = candidate_eu;
if (n->es_v && nmg_find_model(&n->es_v->magic) == original)
n->es_v = (struct vertex *)candidate_structs[n->es_v->index];
if (n->es_fu && nmg_find_model(&n->es_fu->l.magic) == original)
n->es_fu = (struct faceuse *)candidate_structs[n->es_fu->index];
if (n->es_s && nmg_find_model(&n->es_s->l.magic) == original)
n->es_s = (struct shell *)candidate_structs[n->es_s->index];
bu_free(candidate_structs, "NMG candidate structures");
s->es_int.idb_ptr = (void *)candidate;
nmg_km(original);
return 0;
}
static int
ecmd_nmg_emove(struct rt_edit *s)
{
@@ -747,7 +793,7 @@ ecmd_nmg_emove(struct rt_edit *s)
}
}
if (nmg_move_edge_thru_pnt(n->es_eu, new_pt, s->tol) < 0) {
if (nmg_edit_move_edge(s, new_pt)) {
bu_vls_printf(s->log_str, "Edge Move: Unable to hit (%g %g %g)\n",
V3ARGS(new_pt));
return BRLCAD_ERROR;
+12 -8
View File
@@ -234,7 +234,14 @@ rt_edit_rec_edit(struct rt_edit *s)
tgc = (struct rt_tgc_internal *)s->es_int.idb_ptr;
RT_TGC_CK_MAGIC(tgc);
if (s->e_inpara == 3) {
VSCALE(tgc->v, s->e_para, s->local2base);
point_t new_v;
VSCALE(new_v, s->e_para, s->local2base);
if (!isfinite(new_v[X]) || !isfinite(new_v[Y]) ||
!isfinite(new_v[Z])) {
bu_vls_printf(s->log_str, "ERROR: base center must be finite\n");
return BRLCAD_ERROR;
}
VMOVE(tgc->v, new_v);
}
return BRLCAD_OK;
@@ -244,11 +251,8 @@ rt_edit_rec_edit(struct rt_edit *s)
if (s->e_inpara == 3) {
vect_t new_h;
VSCALE(new_h, s->e_para, s->local2base);
if (MAGNITUDE(new_h) < SMALL_FASTF) {
bu_vls_printf(s->log_str,
"ERROR: H vector must have non-zero length\n");
if (edit_validate_height(s, new_h) != BRLCAD_OK)
return BRLCAD_ERROR;
}
mag_a = MAGNITUDE(tgc->a);
mag_b = MAGNITUDE(tgc->b);
@@ -281,7 +285,7 @@ rt_edit_rec_edit(struct rt_edit *s)
RT_TGC_CK_MAGIC(tgc);
if (s->e_inpara == 1) {
r = s->e_para[0] * s->local2base;
if (r < SMALL_FASTF) {
if (!isfinite(r) || r <= 0.0) {
bu_vls_printf(s->log_str,
"ERROR: radius must be positive\n");
return BRLCAD_ERROR;
@@ -298,7 +302,7 @@ rt_edit_rec_edit(struct rt_edit *s)
RT_TGC_CK_MAGIC(tgc);
if (s->e_inpara == 1) {
r = s->e_para[0] * s->local2base;
if (r < SMALL_FASTF) {
if (!isfinite(r) || r <= 0.0) {
bu_vls_printf(s->log_str,
"ERROR: radius must be positive\n");
return BRLCAD_ERROR;
@@ -315,7 +319,7 @@ rt_edit_rec_edit(struct rt_edit *s)
RT_TGC_CK_MAGIC(tgc);
if (s->e_inpara == 1) {
r = s->e_para[0] * s->local2base;
if (r < SMALL_FASTF) {
if (!isfinite(r) || r <= 0.0) {
bu_vls_printf(s->log_str,
"ERROR: radius must be positive\n");
return BRLCAD_ERROR;
+10 -69
View File
@@ -222,16 +222,6 @@ rt_edit_rhc_write_params(
bu_vls_printf(p, "Dist_to_asymptotes: %.9f\n", rhc->rhc_c * base2local);
}
#define read_params_line_incr \
lc = (ln) ? (ln + lcj) : NULL; \
if (!lc) { \
bu_free(wc, "wc"); \
return BRLCAD_ERROR; \
} \
ln = strchr(lc, tc); \
if (ln) *ln = '\0'; \
while (lc && strchr(lc, ':')) lc++
C_DECL int
rt_edit_rhc_read_params(
struct rt_db_internal *ip,
@@ -240,68 +230,19 @@ rt_edit_rhc_read_params(
fastf_t local2base
)
{
double a = 0.0;
double b = 0.0;
double c = 0.0;
struct rt_rhc_internal *rhc = (struct rt_rhc_internal *)ip->idb_ptr;
RT_RHC_CK_MAGIC(rhc);
if (!fc)
struct rt_rhc_internal candidate = *rhc;
const struct edit_param_field fields[] = {
{"Vertex", candidate.rhc_V, ELEMENTS_PER_VECT, local2base},
{"Height", candidate.rhc_H, ELEMENTS_PER_VECT, local2base},
{"Breadth", candidate.rhc_B, ELEMENTS_PER_VECT, local2base},
{"Half-width", &candidate.rhc_r, 1, local2base},
{"Dist_to_asymptotes", &candidate.rhc_c, 1, local2base}
};
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK)
return BRLCAD_ERROR;
// We're getting the file contents as a string, so we need to split it up
// to process lines. See https://stackoverflow.com/a/17983619
// Figure out if we need to deal with Windows line endings
const char *crpos = strchr(fc, '\r');
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
char tc = (crlf) ? '\r' : '\n';
// If we're CRLF jump ahead another character.
int lcj = (crlf) ? 2 : 1;
char *ln = NULL;
char *wc = bu_strdup(fc);
char *lc = wc;
// Set up initial line (Vertex)
ln = strchr(lc, tc);
if (ln) *ln = '\0';
// Trim off prefixes, if user left them in
while (lc && strchr(lc, ':')) lc++;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(rhc->rhc_V, a, b, c);
VSCALE(rhc->rhc_V, rhc->rhc_V, local2base);
// Set up Height line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(rhc->rhc_H, a, b, c);
VSCALE(rhc->rhc_H, rhc->rhc_H, local2base);
// Set up Breadth line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(rhc->rhc_B, a, b, c);
VSCALE(rhc->rhc_B, rhc->rhc_B, local2base);
// Set up Half-width line
read_params_line_incr;
sscanf(lc, "%lf", &a);
rhc->rhc_r = a * local2base;
// Set up distance to asymptotes line
read_params_line_incr;
sscanf(lc, "%lf", &a);
rhc->rhc_c = a * local2base;
// Cleanup
bu_free(wc, "wc");
*rhc = candidate;
return BRLCAD_OK;
}
+9 -63
View File
@@ -195,16 +195,6 @@ rt_edit_rpc_write_params(
}
#define read_params_line_incr \
lc = (ln) ? (ln + lcj) : NULL; \
if (!lc) { \
bu_free(wc, "wc"); \
return BRLCAD_ERROR; \
} \
ln = strchr(lc, tc); \
if (ln) *ln = '\0'; \
while (lc && strchr(lc, ':')) lc++
C_DECL int
rt_edit_rpc_read_params(
struct rt_db_internal *ip,
@@ -213,62 +203,18 @@ rt_edit_rpc_read_params(
fastf_t local2base
)
{
double a = 0.0;
double b = 0.0;
double c = 0.0;
struct rt_rpc_internal *rpc = (struct rt_rpc_internal *)ip->idb_ptr;
RT_RPC_CK_MAGIC(rpc);
if (!fc)
struct rt_rpc_internal candidate = *rpc;
const struct edit_param_field fields[] = {
{"Vertex", candidate.rpc_V, ELEMENTS_PER_VECT, local2base},
{"Height", candidate.rpc_H, ELEMENTS_PER_VECT, local2base},
{"Breadth", candidate.rpc_B, ELEMENTS_PER_VECT, local2base},
{"Half-width", &candidate.rpc_r, 1, local2base}
};
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK)
return BRLCAD_ERROR;
// We're getting the file contents as a string, so we need to split it up
// to process lines. See https://stackoverflow.com/a/17983619
// Figure out if we need to deal with Windows line endings
const char *crpos = strchr(fc, '\r');
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
char tc = (crlf) ? '\r' : '\n';
// If we're CRLF jump ahead another character.
int lcj = (crlf) ? 2 : 1;
char *ln = NULL;
char *wc = bu_strdup(fc);
char *lc = wc;
// Set up initial line (Vertex)
ln = strchr(lc, tc);
if (ln) *ln = '\0';
// Trim off prefixes, if user left them in
while (lc && strchr(lc, ':')) lc++;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(rpc->rpc_V, a, b, c);
VSCALE(rpc->rpc_V, rpc->rpc_V, local2base);
// Set up Height line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(rpc->rpc_H, a, b, c);
VSCALE(rpc->rpc_H, rpc->rpc_H, local2base);
// Set up Breadth line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(rpc->rpc_B, a, b, c);
VSCALE(rpc->rpc_B, rpc->rpc_B, local2base);
// Set up Half-width line
read_params_line_incr;
sscanf(lc, "%lf", &a);
rpc->rpc_r = a * local2base;
// Cleanup
bu_free(wc, "wc");
*rpc = candidate;
return BRLCAD_OK;
}
+32 -96
View File
@@ -460,16 +460,6 @@ rt_edit_tgc_write_params(
bu_vls_printf(p, "D: %.9f %.9f %.9f\n", V3BASE2LOCAL(tgc->d));
}
#define read_params_line_incr \
lc = (ln) ? (ln + lcj) : NULL; \
if (!lc) { \
bu_free(wc, "wc"); \
return BRLCAD_ERROR; \
} \
ln = strchr(lc, tc); \
if (ln) *ln = '\0'; \
while (lc && strchr(lc, ':')) lc++
C_DECL int
rt_edit_tgc_read_params(
struct rt_db_internal *ip,
@@ -478,77 +468,20 @@ rt_edit_tgc_read_params(
fastf_t local2base
)
{
double a = 0.0;
double b = 0.0;
double c = 0.0;
struct rt_tgc_internal *tgc = (struct rt_tgc_internal *)ip->idb_ptr;
RT_TGC_CK_MAGIC(tgc);
if (!fc)
struct rt_tgc_internal candidate = *tgc;
const struct edit_param_field fields[] = {
{"Vertex", candidate.v, ELEMENTS_PER_VECT, local2base},
{"Height", candidate.h, ELEMENTS_PER_VECT, local2base},
{"A", candidate.a, ELEMENTS_PER_VECT, local2base},
{"B", candidate.b, ELEMENTS_PER_VECT, local2base},
{"C", candidate.c, ELEMENTS_PER_VECT, local2base},
{"D", candidate.d, ELEMENTS_PER_VECT, local2base}
};
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK)
return BRLCAD_ERROR;
// We're getting the file contents as a string, so we need to split it up
// to process lines. See https://stackoverflow.com/a/17983619
// Figure out if we need to deal with Windows line endings
const char *crpos = strchr(fc, '\r');
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
char tc = (crlf) ? '\r' : '\n';
// If we're CRLF jump ahead another character.
int lcj = (crlf) ? 2 : 1;
char *ln = NULL;
char *wc = bu_strdup(fc);
char *lc = wc;
// Set up initial line (Vertex)
ln = strchr(lc, tc);
if (ln) *ln = '\0';
// Trim off prefixes, if user left them in
while (lc && strchr(lc, ':')) lc++;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(tgc->v, a, b, c);
VSCALE(tgc->v, tgc->v, local2base);
// Set up Height line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(tgc->h, a, b, c);
VSCALE(tgc->h, tgc->h, local2base);
// Set up A line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(tgc->a, a, b, c);
VSCALE(tgc->a, tgc->a, local2base);
// Set up B line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(tgc->b, a, b, c);
VSCALE(tgc->b, tgc->b, local2base);
// Set up C line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(tgc->c, a, b, c);
VSCALE(tgc->c, tgc->c, local2base);
// Set up D line
read_params_line_incr;
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
VSET(tgc->d, a, b, c);
VSCALE(tgc->d, tgc->d, local2base);
// Cleanup
bu_free(wc, "wc");
*tgc = candidate;
return BRLCAD_OK;
}
@@ -751,7 +684,7 @@ int
ecmd_tgc_mv_h(struct rt_edit *s)
{
float la, lb, lc, ld; /* TGC: length of vectors */
vect_t work;
vect_t work, height;
point_t model_point;
struct rt_tgc_internal *tgc =
(struct rt_tgc_internal *)s->es_int.idb_ptr;
@@ -759,6 +692,7 @@ ecmd_tgc_mv_h(struct rt_edit *s)
void *d = NULL;
RT_TGC_CK_MAGIC(tgc);
VMOVE(height, tgc->h);
if (s->e_inpara) {
if (s->e_inpara != 3) {
bu_vls_printf(s->log_str, "ERROR: three arguments needed\n");
@@ -771,22 +705,21 @@ ecmd_tgc_mv_h(struct rt_edit *s)
if (s->mv_context) {
/* apply s->e_invmat to convert to real model coordinates */
MAT4X3PNT(work, s->e_invmat, model_point);
VSUB2(tgc->h, work, tgc->v);
VSUB2(height, work, tgc->v);
} else {
VSUB2(tgc->h, model_point, tgc->v);
VSUB2(height, model_point, tgc->v);
}
}
/* check for zero H vector */
if (MAGNITUDE(tgc->h) <= SQRT_SMALL_FASTF) {
bu_vls_printf(s->log_str, "Zero H vector not allowed, resetting to +Z\n");
if (edit_validate_height(s, height) != BRLCAD_OK) {
rt_edit_map_clbk_get(&f, &d, s->m, ECMD_PRINT_RESULTS, BU_CLBK_DURING);
if (f)
(*f)(0, NULL, d, NULL);
VSET(tgc->h, 0.0, 0.0, 1.0);
return BRLCAD_ERROR;
}
VMOVE(tgc->h, height);
/* have new height vector -- redefine rest of tgc */
la = MAGNITUDE(tgc->a);
lb = MAGNITUDE(tgc->b);
@@ -814,7 +747,7 @@ ecmd_tgc_mv_h(struct rt_edit *s)
int
ecmd_tgc_mv_hh(struct rt_edit *s)
{
vect_t work;
vect_t work, height;
point_t model_point;
struct rt_tgc_internal *tgc =
(struct rt_tgc_internal *)s->es_int.idb_ptr;
@@ -822,6 +755,7 @@ ecmd_tgc_mv_hh(struct rt_edit *s)
void *d = NULL;
RT_TGC_CK_MAGIC(tgc);
VMOVE(height, tgc->h);
if (s->e_inpara) {
if (s->e_inpara != 3) {
bu_vls_printf(s->log_str, "ERROR: three arguments needed\n");
@@ -834,22 +768,20 @@ ecmd_tgc_mv_hh(struct rt_edit *s)
if (s->mv_context) {
/* apply s->e_invmat to convert to real model coordinates */
MAT4X3PNT(work, s->e_invmat, model_point);
VSUB2(tgc->h, work, tgc->v);
VSUB2(height, work, tgc->v);
} else {
VSUB2(tgc->h, model_point, tgc->v);
VSUB2(height, model_point, tgc->v);
}
}
/* check for zero H vector */
if (MAGNITUDE(tgc->h) <= SQRT_SMALL_FASTF) {
bu_vls_printf(s->log_str, "Zero H vector not allowed, resetting to +Z\n");
if (edit_validate_height(s, height) != BRLCAD_OK) {
rt_edit_map_clbk_get(&f, &d, s->m, ECMD_PRINT_RESULTS, BU_CLBK_DURING);
if (f)
(*f)(0, NULL, d, NULL);
VSET(tgc->h, 0.0, 0.0, 1.0);
return BRLCAD_ERROR;
}
VMOVE(tgc->h, height);
return 0;
}
@@ -1005,7 +937,7 @@ ecmd_tgc_rot_ab(struct rt_edit *s)
}
/* Use mouse to change location of point V+H */
void
static int
ecmd_tgc_mv_h_mousevec(struct rt_edit *s, const vect_t mousevec)
{
struct rt_tgc_internal *tgc =
@@ -1021,8 +953,13 @@ ecmd_tgc_mv_h_mousevec(struct rt_edit *s, const vect_t mousevec)
/* Do NOT change pos_view[Z] ! */
MAT4X3PNT(temp, s->vp->gv_view2model, pos_view);
MAT4X3PNT(tr_temp, s->e_invmat, temp);
VSUB2(tgc->h, tr_temp, tgc->v);
vect_t height;
VSUB2(height, tr_temp, tgc->v);
if (edit_validate_height(s, height) != BRLCAD_OK)
return BRLCAD_ERROR;
VMOVE(tgc->h, height);
edit_abs_tra(s, pos_view);
return BRLCAD_OK;
}
static int
@@ -1188,8 +1125,7 @@ rt_edit_tgc_edit_xy(
break;
case ECMD_TGC_MV_H:
case ECMD_TGC_MV_HH:
ecmd_tgc_mv_h_mousevec(s, mousevec);
return BRLCAD_OK;
return ecmd_tgc_mv_h_mousevec(s, mousevec);
case ECMD_TGC_ROT_H:
case ECMD_TGC_ROT_AB:
bu_vls_printf(s->log_str, "%s: XY edit undefined in solid edit mode %d\n", EDOBJ[ip->idb_type].ft_label, s->edit_flag);
+89
View File
@@ -778,6 +778,72 @@ bu_log("RT_MATRIX_EDIT_TRANS_MODEL_XYZ SUCCESS: "
if (!edit_test_mouse_knobs_match(s, face_view_target))
bu_exit(1, "ERROR: ARB8 mouse face knobs missed cursor\n");
/* A rejected drag must not become the starting geometry for the next. */
struct rt_arb_internal valid_face_arb = *arb;
plane_t valid_face_planes[ARB8_FACE_COUNT];
memcpy(valid_face_planes, a->es_peqn, sizeof(valid_face_planes));
s->local2base = 25.4;
s->base2local = 1.0 / s->local2base;
VSET(mousevec, 1.0, 0.0, 0.0); /* Collapse the moved face onto the opposite face. */
if (EDOBJ[dp->d_minor_type].ft_edit_xy(s, mousevec) != BRLCAD_ERROR ||
memcmp(arb->pt, valid_face_arb.pt, sizeof(arb->pt)) ||
memcmp(a->es_peqn, valid_face_planes, sizeof(valid_face_planes)))
bu_exit(1, "ERROR: rejected ARB8 mouse face move changed edit state\n");
const fastf_t face_drags[] = {0.3, 0.4, 0.25};
const size_t drag_cycles = 32;
const size_t drag_positions = sizeof(face_drags) / sizeof(face_drags[0]);
for (size_t drag = 0; drag < drag_cycles * drag_positions; drag++) {
fastf_t target_x = face_drags[drag % drag_positions];
VSET(mousevec, target_x, 0.0, 0.0);
if (EDOBJ[dp->d_minor_type].ft_edit_xy(s, mousevec) != BRLCAD_OK ||
rt_edit_process(s) != BRLCAD_OK)
bu_exit(1, "ERROR: ARB8 mouse face move failed after rejected drag\n");
for (size_t i = 0; i < sizeof(face_points) / sizeof(face_points[0]); i++) {
if (!NEAR_EQUAL(arb->pt[face_points[i]][X], target_x, VUNITIZE_TOL))
bu_exit(1, "ERROR: repeated ARB8 mouse face move drifted\n");
}
}
struct rt_arb_internal before_rejected_calc = *arb;
plane_t rejected_planes[ARB8_FACE_COUNT];
memcpy(rejected_planes, a->es_peqn, sizeof(rejected_planes));
rejected_planes[a->edit_menu][W] = VDOT(rejected_planes[a->edit_menu], arb->pt[1]);
if (rt_arb_calc_points(arb, ARB8, (const plane_t *)rejected_planes, s->tol) >= 0 ||
memcmp(arb->pt, before_rejected_calc.pt, sizeof(arb->pt)))
bu_exit(1, "ERROR: rejected ARB point calculation changed geometry\n");
struct rt_arb_internal invalid_arb = *arb;
VMOVE(invalid_arb.pt[6], invalid_arb.pt[5]);
VMOVE(invalid_arb.pt[0], invalid_arb.pt[4]);
memcpy(rejected_planes, a->es_peqn, sizeof(rejected_planes));
plane_t unchanged_planes[ARB8_FACE_COUNT];
memcpy(unchanged_planes, rejected_planes, sizeof(unchanged_planes));
struct bu_vls rejected_plane_msg = BU_VLS_INIT_ZERO;
if (rt_arb_calc_planes(&rejected_plane_msg, &invalid_arb, ARB8,
rejected_planes, s->tol) >= 0 ||
memcmp(rejected_planes, unchanged_planes, sizeof(rejected_planes)))
bu_exit(1, "ERROR: rejected ARB plane calculation changed planes\n");
bu_vls_free(&rejected_plane_msg);
struct rt_arb_internal before_rejected_edge = *arb;
memcpy(rejected_planes, a->es_peqn, sizeof(rejected_planes));
VSET(mousevec, 0.0, 1.0, 0.0); /* Move edge 12 onto the opposite edge. */
if (rt_arb_edit(s->log_str, arb, NULL, ARB8, 0,
RT_ARB_EDIT_DEFAULT, mousevec, rejected_planes, s->tol) == 0 ||
memcmp(arb->pt, before_rejected_edge.pt, sizeof(arb->pt)) ||
memcmp(rejected_planes, a->es_peqn, sizeof(rejected_planes)))
bu_exit(1, "ERROR: rejected ARB edge edit changed geometry or planes\n");
memcpy(rejected_planes, a->es_peqn, sizeof(rejected_planes));
VSETALL(mousevec, 0.0);
if (rt_arb_edit(s->log_str, arb, NULL, ARB8, 0,
RT_ARB_EDIT_EDGE_DIR, mousevec, rejected_planes, s->tol) == 0 ||
!ZERO(MAGNITUDE(mousevec)) ||
memcmp(arb->pt, before_rejected_edge.pt, sizeof(arb->pt)) ||
memcmp(rejected_planes, a->es_peqn, sizeof(rejected_planes)))
bu_exit(1, "ERROR: rejected ARB edge direction changed input or edit state\n");
s->local2base = 1.0;
s->base2local = 1.0;
@@ -844,6 +910,29 @@ bu_log("RT_MATRIX_EDIT_TRANS_MODEL_XYZ SUCCESS: "
ZERO(a->es_peqn[4][Y]))
bu_exit(1, "ERROR: ARB extended face rotation changed input or left plane unchanged\n");
arb8_reset(s, arb, a);
a->edit_menu = 0; /* Rotate the bottom plane onto a side plane. */
a->fixv = 0;
rt_edit_set_edflag(s, ECMD_ARB_ROTATE_FACE);
s->mv_context = 0;
s->e_inpara = 3;
VSET(s->e_para, 0.0, 90.0, 0.0);
MAT_IDN(s->acc_rot_sol);
MAT_IDN(s->model_changes);
MAT_IDN(s->incr_change);
if (rt_arb_calc_planes(s->log_str, arb, ARB8, a->es_peqn, s->tol))
bu_exit(1, "ERROR: ARB rejected-rotation setup failed\n");
struct rt_arb_internal before_rejected_rotation = *arb;
plane_t before_rotation_planes[ARB8_FACE_COUNT];
mat_t before_rotation_acc;
memcpy(before_rotation_planes, a->es_peqn, sizeof(before_rotation_planes));
MAT_COPY(before_rotation_acc, s->acc_rot_sol);
if (rt_edit_process(s) != BRLCAD_ERROR ||
memcmp(arb->pt, before_rejected_rotation.pt, sizeof(arb->pt)) ||
memcmp(a->es_peqn, before_rotation_planes, sizeof(before_rotation_planes)) ||
memcmp(s->acc_rot_sol, before_rotation_acc, sizeof(before_rotation_acc)))
bu_exit(1, "ERROR: rejected ARB face rotation changed edit state\n");
/* The same face operation must survive the interactive rotation knob
* adapter, which supplies an incremental matrix rather than parameters.
*/
+14
View File
@@ -402,6 +402,20 @@ rt_edit_test_bot(void)
V3ARGS(&bot->vertices[4*3]));
}
bot_reset(s, bot, b);
/* An edge selection can become stale after a topology change. */
bot->faces[0] = 0; bot->faces[1] = 2; bot->faces[2] = 3;
bot->faces[3] = 1; bot->faces[4] = 2; bot->faces[5] = 3;
int faces_before[12];
memcpy(faces_before, bot->faces, sizeof(faces_before));
b->bot_verts[0] = 0;
b->bot_verts[1] = 1;
EDOBJ[dp->d_minor_type].ft_set_edit_mode(s, ECMD_BOT_ESPLIT);
if (rt_edit_process(s) != BRLCAD_ERROR ||
bot->num_vertices != 4 || bot->num_faces != 4 ||
memcmp(bot->faces, faces_before, sizeof(faces_before)))
bu_exit(1, "ERROR: stale BOT edge split changed topology\n");
/* ================================================================
* ECMD_BOT_FSPLIT: split face {0,2,3} of a fresh tetrahedron
*
+21
View File
@@ -258,6 +258,27 @@ rt_edit_test_cline(void)
rt_edit_process(s);
if (cline_diff("ECMD_CLINE_MOVE_H", cmp, edit_cline))
bu_exit(1, "ERROR: ECMD_CLINE_MOVE_H failed\n");
cline_reset(s, edit_cline, orig, cmp);
s->e_inpara = 3;
s->local2base = 25.4;
s->base2local = 1.0 / s->local2base;
VSCALE(s->e_para, orig->v, s->base2local);
if (rt_edit_process(s) != BRLCAD_ERROR ||
cline_diff("rejected zero-height move", cmp, edit_cline))
bu_exit(1, "ERROR: rejected CLINE height move changed geometry\n");
s->local2base = 1.0;
s->base2local = 1.0;
cline_reset(s, edit_cline, orig, cmp);
VMOVE(s->curr_e_axes_pos, orig->v);
point_t rejected_view_target;
MAT4X3PNT(rejected_view_target, v->gv_model2view, orig->v);
VMOVE(mousevec, rejected_view_target);
if (EDOBJ[dp->d_minor_type].ft_edit_xy(s, mousevec) != BRLCAD_ERROR ||
cline_diff("rejected mouse zero-height move", cmp, edit_cline))
bu_exit(1, "ERROR: rejected CLINE mouse height move changed geometry\n");
VADD2(s->curr_e_axes_pos, orig->v, orig->h);
bu_log("ECMD_CLINE_MOVE_H SUCCESS: h=%g,%g,%g\n", V3ARGS(edit_cline->h));
/* ================================================================
+21
View File
@@ -232,6 +232,27 @@ rt_edit_test_extrude(void)
rt_edit_process(s);
if (extr_diff("ECMD_EXTR_MOV_H", cmp, edit_extr))
bu_exit(1, "ERROR: ECMD_EXTR_MOV_H failed\n");
extr_reset(s, edit_extr, orig, cmp);
s->e_inpara = 3;
s->local2base = 25.4;
s->base2local = 1.0 / s->local2base;
VSCALE(s->e_para, orig->V, s->base2local);
if (rt_edit_process(s) != BRLCAD_ERROR ||
extr_diff("rejected zero-height move", cmp, edit_extr))
bu_exit(1, "ERROR: rejected EXTRUDE height move changed geometry\n");
s->local2base = 1.0;
s->base2local = 1.0;
extr_reset(s, edit_extr, orig, cmp);
VMOVE(s->curr_e_axes_pos, orig->V);
point_t rejected_view_target;
MAT4X3PNT(rejected_view_target, v->gv_model2view, orig->V);
VMOVE(mousevec, rejected_view_target);
if (EDOBJ[dp->d_minor_type].ft_edit_xy(s, mousevec) != BRLCAD_ERROR ||
extr_diff("rejected mouse zero-height move", cmp, edit_extr))
bu_exit(1, "ERROR: rejected EXTRUDE mouse height move changed geometry\n");
VADD2(s->curr_e_axes_pos, orig->V, orig->h);
bu_log("ECMD_EXTR_MOV_H SUCCESS: h=%g,%g,%g\n", V3ARGS(edit_extr->h));
/* ================================================================
+67 -5
View File
@@ -144,16 +144,66 @@ check_unit(fastf_t local2base, const char *unit)
rt_edit_checkpoint(edit) != BRLCAD_OK)
++failures;
uint8_t *saved_checkpoint = edit->es_ckpt.ext_buf;
size_t saved_size = edit->es_ckpt.ext_nbytes;
/* Force export failure without altering the saved checkpoint. */
edit->es_int.idb_type = -1;
int checkpoint_result = rt_edit_checkpoint(edit);
edit->es_int.idb_type = ID_ELL;
if (checkpoint_result != BRLCAD_ERROR ||
edit->es_ckpt.ext_buf != saved_checkpoint ||
edit->es_ckpt.ext_nbytes != saved_size || !same_ell(edit, 4))
++failures;
/* This placeholder has no importer; failed revert must preserve ELL. */
edit->es_int.idb_type = ID_UNUSED1;
int revert_result = rt_edit_revert(edit);
edit->es_int.idb_type = ID_ELL;
if (revert_result != BRLCAD_ERROR || !same_ell(edit, 4) ||
edit->es_ckpt.ext_buf != saved_checkpoint)
++failures;
bu_log("failed checkpoint/revert preserve state\t%s\t%s\n", unit,
failures ? "fail" : "pass");
rt_edit_set_edflag(edit, RT_PARAMS_EDIT_SCALE);
edit->update_views = 0;
edit->e_inpara = 2;
edit->e_mvalid = 1;
edit->es_scale = 2.0;
edit->e_para[0] = 2.0;
edit->e_para[1] = 3.0;
if (rt_edit_process(edit) != BRLCAD_ERROR ||
edit->e_inpara || edit->e_mvalid || !ZERO(edit->es_scale) ||
edit->update_views || !EQUAL(edit->e_para[0], 2.0) ||
!same_ell(edit, 4))
++failures;
rt_edit_set_edflag(edit, ECMD_ELL_SCALE_A);
if (rt_edit_process(edit) != BRLCAD_OK || !same_ell(edit, 4) ||
edit->update_views != 1)
++failures;
if (rt_edit_process(edit) != BRLCAD_OK || edit->update_views != 1)
++failures;
bu_log("failed edit consumes input\t%s\t%s\n", unit,
failures ? "fail" : "pass");
const fastf_t target_length = 2.0 * inch_to_mm;
rt_edit_set_edflag(edit, ECMD_ELL_SCALE_A);
edit->mv_context = 1;
edit->e_inpara = 1;
edit->e_para[0] = target_length / local2base;
if (rt_edit_process(edit) != BRLCAD_OK ||
!same_ell(edit, target_length) ||
!NEAR_EQUAL(edit->e_para[0], target_length / local2base,
VUNITIZE_TOL) ||
rt_edit_revert(edit) != BRLCAD_OK || !same_ell(edit, 4))
int edit_result = rt_edit_process(edit);
bool scaled = same_ell(edit, target_length) &&
NEAR_EQUAL(edit->e_para[0], target_length / local2base,
VUNITIZE_TOL);
edit->acc_sc_sol = 2.5;
VSET(edit->e_keypoint, -1, -1, -1);
point_t original_keypoint = {10, 5, 20};
if (edit_result != BRLCAD_OK || !scaled ||
rt_edit_revert(edit) != BRLCAD_OK || !same_ell(edit, 4) ||
!EQUAL(edit->acc_sc_sol, 1.0) ||
!VNEAR_EQUAL(edit->e_keypoint, original_keypoint, VUNITIZE_TOL))
++failures;
if (rt_edit_revert(edit) != BRLCAD_OK || !same_ell(edit, 4))
++failures;
bu_log("checkpoint/edit/revert\t%s\t%s\n", unit,
failures ? "fail" : "pass");
@@ -194,6 +244,18 @@ int
rt_edit_test_lifecycle_matrix(void)
{
int failures = check_map();
struct rt_edit *idle = rt_edit_create(NULL, NULL, NULL, NULL);
if (!idle)
return BRLCAD_ERROR;
idle->e_inpara = 1;
idle->e_mvalid = 1;
idle->es_scale = 2.0;
if (rt_edit_process(NULL) != BRLCAD_ERROR ||
rt_edit_process(idle) != BRLCAD_ERROR ||
idle->e_inpara || idle->e_mvalid || !ZERO(idle->es_scale) ||
idle->update_views)
++failures;
rt_edit_destroy(idle);
failures += check_unit(1.0, "mm");
failures += check_unit(inch_to_mm, "in");
return failures ? BRLCAD_ERROR : BRLCAD_OK;
+94
View File
@@ -282,6 +282,29 @@ nmg_tet_state(const struct rt_edit *edit,
nmg_points_match(edit, expected, NMG_TET_VERTEX_COUNT);
}
static bool
nmg_tet_face_planes(const struct model *model,
fastf_t planes[NMG_TET_FACE_COUNT][ELEMENTS_PER_PLANE])
{
size_t count = 0;
struct nmgregion *region;
for (BU_LIST_FOR(region, nmgregion, &model->r_hd)) {
struct shell *shell;
for (BU_LIST_FOR(shell, shell, &region->s_hd)) {
struct faceuse *face;
for (BU_LIST_FOR(face, faceuse, &shell->fu_hd)) {
if (face->orientation != OT_SAME)
continue;
if (count == NMG_TET_FACE_COUNT || !face->f_p->g.plane_p)
return false;
memcpy(planes[count++], face->f_p->g.plane_p->N,
sizeof(plane_t));
}
}
}
return count == NMG_TET_FACE_COUNT;
}
static int
nmg_tet_step(struct rt_edit *edit, const char *unit, const char *name,
int command, const fastf_t *params, int count,
@@ -354,6 +377,34 @@ nmg_operation_matrix_unit(fastf_t local2base, const char *unit)
ECMD_NMG_EKILL, NULL, 0, expected, -1, false, true);
failures += nmg_tet_step(edit, unit, "reject extrusion without loop",
ECMD_NMG_LEXTRU_DIR, extrude_direction, 4, expected, -1, false, true);
/* A target at the opposite face vertex makes its new plane degenerate. */
struct rt_nmg_edit *selection = (struct rt_nmg_edit *)edit->ipe_ptr;
struct model *model = (struct model *)edit->es_int.idb_ptr;
struct nmgregion *region = BU_LIST_FIRST(nmgregion, &model->r_hd);
struct shell *shell = BU_LIST_FIRST(shell, &region->s_hd);
struct faceuse *face = BU_LIST_FIRST(faceuse, &shell->fu_hd);
if (face->orientation != OT_SAME)
face = face->fumate_p;
struct loopuse *loop = BU_LIST_FIRST(loopuse, &face->lu_hd);
selection->es_eu = BU_LIST_FIRST(edgeuse, &loop->down_hd);
struct edgeuse *next = BU_LIST_PNEXT_CIRC(edgeuse, &selection->es_eu->l);
point_t degenerate_target;
VSCALE(degenerate_target, next->eumate_p->vu_p->v_p->vg_p->coord,
1.0 / local2base);
fastf_t before_planes[NMG_TET_FACE_COUNT][ELEMENTS_PER_PLANE];
fastf_t after_planes[NMG_TET_FACE_COUNT][ELEMENTS_PER_PLANE];
bool have_planes = nmg_tet_face_planes(model, before_planes);
failures += nmg_tet_step(edit, unit, "reject degenerate edge move",
ECMD_NMG_EMOVE, degenerate_target, 3, expected, -1, false, true);
if (!have_planes || !nmg_tet_face_planes(
(struct model *)edit->es_int.idb_ptr, after_planes) ||
memcmp(before_planes, after_planes, sizeof(before_planes))) {
bu_log("nmg\treject degenerate edge move planes\t%s\tfail\n", unit);
++failures;
}
selection->es_eu = NULL;
failures += nmg_tet_step(edit, unit, "reject fractional vertex index",
ECMD_NMG_VPICK, bad_pick, 1, expected, -1, false, true);
failures += nmg_tet_step(edit, unit, "pick vertex",
@@ -375,6 +426,45 @@ nmg_operation_matrix_unit(fastf_t local2base, const char *unit)
failures += nmg_tet_step(edit, unit, "move face",
ECMD_NMG_FMOVE, face_delta, 3, expected, 1, true);
/* A successful face-edge move must remap all live NMG selections. */
model = (struct model *)edit->es_int.idb_ptr;
region = BU_LIST_FIRST(nmgregion, &model->r_hd);
shell = BU_LIST_FIRST(shell, &region->s_hd);
face = BU_LIST_FIRST(faceuse, &shell->fu_hd);
if (face->orientation != OT_SAME)
face = face->fumate_p;
loop = BU_LIST_FIRST(loopuse, &face->lu_hd);
selection->es_eu = BU_LIST_FIRST(edgeuse, &loop->down_hd);
point_t edge_target;
VMOVE(edge_target, selection->es_eu->vu_p->v_p->vg_p->coord);
edge_target[Y] += 0.1;
edge_target[Z] += 0.1;
rt_edit_set_edflag(edit, ECMD_NMG_EMOVE);
edit->e_inpara = 3;
VSCALE(edit->e_para, edge_target, 1.0 / local2base);
int edge_result = rt_edit_process(edit);
struct model *moved_model = (struct model *)edit->es_int.idb_ptr;
if (edge_result != BRLCAD_OK || moved_model == model ||
nmg_find_model(&selection->es_eu->l.magic) != moved_model ||
nmg_find_model(&selection->es_v->magic) != moved_model ||
nmg_find_model(&selection->es_fu->l.magic) != moved_model) {
bu_log("nmg\tmove face edge and remap selections\t%s\tfail\n", unit);
++failures;
}
if (rt_edit_checkpoint(edit) != BRLCAD_OK) {
bu_log("nmg\tcheckpoint selected model\t%s\tfail\n", unit);
++failures;
} else {
selection->es_v->vg_p->coord[X] += 1.0;
if (rt_edit_revert(edit) != BRLCAD_OK || selection->es_eu ||
selection->es_v || selection->es_fu ||
!edit->es_int.idb_ptr) {
bu_log("nmg\trevert clears selected topology\t%s\tfail\n", unit);
++failures;
}
}
rt_edit_destroy(edit);
db_free_full_path(&path);
db_close(dbip);
@@ -702,6 +792,7 @@ rt_edit_test_nmg(void)
bu_list_len(&wire_loop->down_hd) != edge_count ||
!nmg_points_match(ws, wire_expected, NMG_WIRE_VERTEX_COUNT))
bu_exit(1, "ERROR: NMG accepted a nonfinite edge split\n");
ws->e_inpara = 3;
VSCALE(ws->e_para, edge_midpoint, 1.0 / local2base);
point_t split_input;
VMOVE(split_input, ws->e_para);
@@ -765,6 +856,7 @@ rt_edit_test_nmg(void)
if (rt_edit_process(ws) == BRLCAD_OK ||
!nmg_points_match(ws, wire_expected, NMG_WIRE_VERTEX_COUNT))
bu_exit(1, "ERROR: NMG accepted a zero extrusion direction\n");
ws->e_inpara = 4;
ws->e_para[0] = 0.0; /* dir X */
ws->e_para[1] = 0.0; /* dir Y */
ws->e_para[2] = 1.0; /* dir Z */
@@ -807,6 +899,7 @@ rt_edit_test_nmg(void)
!nmg_points_match(ws, wire_and_prism_expected,
NMG_WIRE_AND_PRISM_VERTEX_COUNT))
bu_exit(1, "ERROR: NMG invalid preview target changed the solid\n");
ws->e_inpara = 4;
ws->e_para[Z] = 1.0;
if (rt_edit_process(ws) != BRLCAD_OK)
bu_exit(1, "ERROR: NMG repeated extrusion failed\n");
@@ -834,6 +927,7 @@ rt_edit_test_nmg(void)
!nmg_points_match(ws, wire_and_prism_expected,
NMG_WIRE_AND_PRISM_VERTEX_COUNT))
bu_exit(1, "ERROR: NMG accepted a nonfinite extrusion distance\n");
ws->e_inpara = 1;
ws->e_para[0] = 1.0 / local2base;
if (rt_edit_process(ws) != BRLCAD_OK)
bu_exit(1, "ERROR: NMG scalar extrusion failed\n");
+70
View File
@@ -26,6 +26,7 @@
#include "common.h"
#include <string>
#include <string.h>
#include "bu/log.h"
@@ -262,6 +263,56 @@ same_arb_vertices(const struct rt_arb_internal *arb,
return true;
}
static int
check_atomic_param_rejection(const struct param_case *test,
struct rt_db_internal *ip, const struct bn_tol *tol,
fastf_t local2base, const char *output)
{
std::string truncated(output);
if (!truncated.empty() && truncated.back() == '\n')
truncated.pop_back();
size_t last_line = truncated.find_last_of('\n');
if (last_line == std::string::npos)
return 1;
truncated.erase(last_line + 1);
const std::string invalid[] = {
truncated,
truncated + "invalid\n",
std::string(output) + "unexpected: 1\n"
};
void *before = bu_malloc(test->parsed_size, "parameter reader snapshot");
memcpy(before, test->parsed, test->parsed_size);
int failures = 0;
for (const std::string &text : invalid) {
memcpy(test->parsed, before, test->parsed_size);
int result = EDOBJ[test->type].ft_read_params(ip, text.c_str(), tol,
local2base);
if (result != BRLCAD_ERROR || !test->same(test->parsed, before))
failures++;
}
memcpy(test->parsed, before, test->parsed_size);
bu_free(before, "parameter reader snapshot");
return failures;
}
static bool
check_atomic_reader_type(int type)
{
switch (type) {
case ID_EPA:
case ID_EHY:
case ID_ETO:
case ID_HYP:
case ID_RPC:
case ID_RHC:
case ID_TGC:
return true;
default:
return false;
}
}
static int
run_case(const struct param_case *test, fastf_t local2base, const char *unit)
{
@@ -296,6 +347,25 @@ run_case(const struct param_case *test, fastf_t local2base, const char *unit)
bu_log("%s\tparams\t%s\twrong reconstructed geometry\n", test->name, unit);
failed = 1;
}
if (check_atomic_reader_type(test->type)) {
std::string crlf;
for (const char *p = output; *p; ++p) {
if (*p == '\n')
crlf.push_back('\r');
crlf.push_back(*p);
}
if (edit->ft_read_params(&ip, crlf.c_str(), &tol, local2base) != BRLCAD_OK ||
!test->same(test->original, test->parsed)) {
bu_log("%s\tparams\t%s\tCRLF reconstruction failed\n", test->name, unit);
failed = 1;
}
}
if (check_atomic_reader_type(test->type) &&
check_atomic_param_rejection(test, &ip, &tol, local2base, output)) {
bu_log("%s\tparams\t%s\trejected edit changed geometry\n",
test->name, unit);
failed = 1;
}
if (!failed)
bu_log("%s\tparams\t%s\tpass\n", test->name, unit);
bu_vls_free(&text);
+11
View File
@@ -1305,6 +1305,17 @@ bu_log("RT_MATRIX_EDIT_TRANS_MODEL_XYZ SUCCESS: "
!NEAR_EQUAL(pipe_second(s)->pp_bendradius, 0.5 * inch, SMALL_FASTF))
bu_exit(1, "ERROR: inch whole-pipe bend could not be set from zero\n");
pipe_full_reset(s, pe);
if (rt_edit_checkpoint(s) != BRLCAD_OK)
bu_exit(1, "ERROR: pipe checkpoint failed\n");
pe->es_pipe_pnt = pipe_second(s);
pipe_first(s)->pp_coord[X] = inch;
VSET(s->e_keypoint, -1, -1, -1);
if (rt_edit_revert(s) != BRLCAD_OK || pe->es_pipe_pnt ||
!ZERO(pipe_first(s)->pp_coord[X]) ||
!VNEAR_ZERO(s->e_keypoint, VUNITIZE_TOL))
bu_exit(1, "ERROR: pipe revert retained stale geometry or selection\n");
int matrix_failures = pipe_transform_matrix(dbip, &fp, &tol, v);
matrix_failures += pipe_dimension_matrix(dbip, &fp, &tol);
matrix_failures += pipe_point_matrix(dbip, &fp, &tol);
+39
View File
@@ -24,6 +24,9 @@
#include "common.h"
#include <math.h>
#include <string.h>
#include "vmath.h"
#include "bu/log.h"
#include "bu/malloc.h"
@@ -156,6 +159,32 @@ check_rec_units(const fastf_t local2base)
!NEAR_EQUAL(MAGNITUDE(rec->b), 2.5 * inch, VUNITIZE_TOL))
bu_exit(1, "REC equal-radius edit did not use local units\n");
const struct rt_tgc_internal saved_rec = *rec;
EDOBJ[ID_REC].ft_set_edit_mode(s, ECMD_REC_SET_V);
s->e_inpara = 3;
VSET(s->e_para, NAN, 0.0, 0.0);
if (EDOBJ[ID_REC].ft_edit(s) != BRLCAD_ERROR ||
memcmp(rec, &saved_rec, sizeof(saved_rec)))
bu_exit(1, "REC accepted an invalid center or changed geometry\n");
EDOBJ[ID_REC].ft_set_edit_mode(s, ECMD_REC_SET_H);
VSET(s->e_para, 0.0, 0.0, tol.dist * 0.5 / local2base);
if (EDOBJ[ID_REC].ft_edit(s) != BRLCAD_ERROR ||
memcmp(rec, &saved_rec, sizeof(saved_rec)))
bu_exit(1, "REC accepted a near-zero height or changed geometry\n");
const int radius_commands[] = {
ECMD_REC_SCALE_R1, ECMD_REC_SCALE_R2, ECMD_REC_SCALE_R
};
for (size_t i = 0; i < sizeof(radius_commands) / sizeof(radius_commands[0]); i++) {
EDOBJ[ID_REC].ft_set_edit_mode(s, radius_commands[i]);
s->e_inpara = 1;
s->e_para[0] = NAN;
if (EDOBJ[ID_REC].ft_edit(s) != BRLCAD_ERROR ||
memcmp(rec, &saved_rec, sizeof(saved_rec)))
bu_exit(1, "REC accepted an invalid radius or changed geometry\n");
}
s->e_inpara = 1;
s->e_para[0] = 0.0;
if (EDOBJ[ID_REC].ft_edit(s) != BRLCAD_ERROR ||
@@ -175,6 +204,16 @@ check_rec_units(const fastf_t local2base)
EDOBJ[ID_REC].ft_edit_get_params(s, ECMD_REC_SCALE_R, NULL) >= 0)
bu_exit(1, "REC getter accepted invalid arguments\n");
point_t saved_center;
VMOVE(saved_center, rec->v);
if (rt_edit_checkpoint(s) != BRLCAD_OK)
bu_exit(1, "REC checkpoint failed\n");
rec->v[X] += inch;
if (rt_edit_revert(s) != BRLCAD_OK || s->es_int.idb_type != ID_REC ||
!VNEAR_EQUAL(((struct rt_tgc_internal *)s->es_int.idb_ptr)->v,
saved_center, VUNITIZE_TOL))
bu_exit(1, "REC revert lost its type or geometry\n");
rt_edit_destroy(s);
db_free_full_path(&fp);
db_close(dbip);
+10
View File
@@ -420,6 +420,16 @@ rt_edit_test_sph(void)
bu_exit(1, "SPH radius command did not restore degenerate axes\n");
}
point_t saved_center;
VMOVE(saved_center, ell->v);
if (rt_edit_checkpoint(s) != BRLCAD_OK)
bu_exit(1, "SPH checkpoint failed\n");
ell->v[X] += 1.0;
if (rt_edit_revert(s) != BRLCAD_OK || s->es_int.idb_type != ID_SPH ||
!VNEAR_EQUAL(((struct rt_ell_internal *)s->es_int.idb_ptr)->v,
saved_center, VUNITIZE_TOL))
bu_exit(1, "SPH revert lost its type or geometry\n");
rt_edit_destroy(s);
db_close(dbip);
return 0;
+28
View File
@@ -386,6 +386,34 @@ rt_edit_test_tgc(void)
bu_exit(1, "ERROR: ECMD_TGC_MV_HH failed\n");
bu_log("ECMD_TGC_MV_HH SUCCESS: h=%g,%g,%g\n", V3ARGS(edit_tgc->h));
const int height_moves[] = {ECMD_TGC_MV_H, ECMD_TGC_MV_HH};
for (size_t i = 0; i < sizeof(height_moves) / sizeof(height_moves[0]); i++) {
tgc_reset(s, edit_tgc, orig_tgc, cmp_tgc);
EDOBJ[dp->d_minor_type].ft_set_edit_mode(s, height_moves[i]);
s->local2base = 25.4;
s->base2local = 1.0 / s->local2base;
s->e_inpara = 3;
VSCALE(s->e_para, orig_tgc->v, s->base2local);
int result = rt_edit_process(s);
if (result != BRLCAD_ERROR ||
tgc_diff("rejected zero-height move", cmp_tgc, edit_tgc))
bu_exit(1, "ERROR: rejected TGC height move changed geometry (mode %d, result %d, h %g %g %g)\n",
height_moves[i], result, V3ARGS(edit_tgc->h));
s->local2base = 1.0;
s->base2local = 1.0;
}
tgc_reset(s, edit_tgc, orig_tgc, cmp_tgc);
EDOBJ[dp->d_minor_type].ft_set_edit_mode(s, ECMD_TGC_MV_H);
VMOVE(s->curr_e_axes_pos, orig_tgc->v);
point_t rejected_view_target;
MAT4X3PNT(rejected_view_target, v->gv_model2view, orig_tgc->v);
VMOVE(mousevec, rejected_view_target);
if (EDOBJ[dp->d_minor_type].ft_edit_xy(s, mousevec) != BRLCAD_ERROR ||
tgc_diff("rejected mouse zero-height move", cmp_tgc, edit_tgc))
bu_exit(1, "ERROR: rejected TGC mouse height move changed geometry\n");
VADD2(s->curr_e_axes_pos, orig_tgc->v, orig_tgc->h);
/* ================================================================
* ECMD_TGC_ROT_H (rotate H vector by (5,5,5) degrees about keypoint=v)
* h_new = R * h where R = bn_mat_angles(5,5,5)
+16
View File
@@ -240,6 +240,22 @@ rt_edit_test_vol(void)
bu_log("RT_PARAMS_EDIT_SCALE SUCCESS: mat[15]=%g (encodes scale=2)\n",
edit_vol->mat[15]);
vol_reset(s, edit_vol);
s->e_inpara = 2;
s->e_para[0] = 2.0;
s->e_para[1] = 3.0;
if (rt_edit_process(s) != BRLCAD_ERROR ||
!NEAR_EQUAL(edit_vol->mat[15], 1.0, VUNITIZE_TOL))
bu_exit(1, "ERROR: rejected generic VOL scale changed geometry or succeeded\n");
vol_reset(s, edit_vol);
s->e_inpara = 1;
s->e_para[0] = 0.0;
if (rt_edit_process(s) != BRLCAD_ERROR ||
!NEAR_EQUAL(edit_vol->mat[15], 1.0, VUNITIZE_TOL) ||
!NEAR_EQUAL(s->acc_sc_sol, 1.0, VUNITIZE_TOL))
bu_exit(1, "ERROR: rejected zero VOL scale changed edit state\n");
/* ================================================================
* RT_PARAMS_EDIT_TRANS (translate; keypoint (0,0,0) → e_para=(5,5,5))
*