Fix knife angle constraint bug #33813 by changing knife mvals to floats.

The problem was that by snapping the integer mouse values to
lines through the previous point, the angle was slightly off.
This commit is contained in:
Howard Trickey 2013-01-11 14:13:22 +00:00
parent f68e9db583
commit d1d3384750

@ -128,7 +128,7 @@ typedef struct KnifePosData {
BMFace *bmface; BMFace *bmface;
int is_space; int is_space;
int mval[2]; /* mouse screen position */ float mval[2]; /* mouse screen position (may be non-integral if snapped to something) */
} KnifePosData; } KnifePosData;
/* struct for properties used while drawing */ /* struct for properties used while drawing */
@ -204,10 +204,10 @@ typedef struct KnifeTool_OpData {
static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, BMFace *f); static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, BMFace *f);
#if 0 #if 0
static void knife_input_ray_cast(KnifeTool_OpData *kcd, const int mval_i[2], static void knife_input_ray_cast(KnifeTool_OpData *kcd, const float mval[2],
float r_origin[3], float r_ray[3]); float r_origin[3], float r_ray[3]);
#endif #endif
static void knife_input_ray_segment(KnifeTool_OpData *kcd, const int mval_i[2], const float ofs, static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2], const float ofs,
float r_origin[3], float r_dest[3]); float r_origin[3], float r_dest[3]);
static void knife_update_header(bContext *C, KnifeTool_OpData *kcd) static void knife_update_header(bContext *C, KnifeTool_OpData *kcd)
@ -225,6 +225,10 @@ static void knife_update_header(bContext *C, KnifeTool_OpData *kcd)
ED_area_headerprint(CTX_wm_area(C), header); ED_area_headerprint(CTX_wm_area(C), header);
} }
static inline int round_ftoi(float x)
{
return x > 0.0f ? (int)(x + 0.5f) : (int)(x - 0.5f);
}
static void knife_project_v3(KnifeTool_OpData *kcd, const float co[3], float sco[3]) static void knife_project_v3(KnifeTool_OpData *kcd, const float co[3], float sco[3])
{ {
@ -238,8 +242,8 @@ static void knife_pos_data_clear(KnifePosData *kpd)
kpd->vert = NULL; kpd->vert = NULL;
kpd->edge = NULL; kpd->edge = NULL;
kpd->bmface = NULL; kpd->bmface = NULL;
kpd->mval[0] = 0; kpd->mval[0] = 0.0f;
kpd->mval[1] = 0; kpd->mval[1] = 0.0f;
} }
static ListBase *knife_empty_list(KnifeTool_OpData *kcd) static ListBase *knife_empty_list(KnifeTool_OpData *kcd)
@ -1420,17 +1424,14 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
/* this works but gives numeric problems [#33400] */ /* this works but gives numeric problems [#33400] */
#if 0 #if 0
static void knife_input_ray_cast(KnifeTool_OpData *kcd, const int mval_i[2], static void knife_input_ray_cast(KnifeTool_OpData *kcd, const float mval[2],
float r_origin[3], float r_ray[3]) float r_origin[3], float r_ray[3])
{ {
bglMats mats; bglMats mats;
float mval[2], imat[3][3]; float imat[3][3];
knife_bgl_get_mats(kcd, &mats); knife_bgl_get_mats(kcd, &mats);
mval[0] = (float)mval_i[0];
mval[1] = (float)mval_i[1];
/* unproject to find view ray */ /* unproject to find view ray */
ED_view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f); ED_view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f);
@ -1452,17 +1453,13 @@ static void knife_input_ray_cast(KnifeTool_OpData *kcd, const int mval_i[2],
} }
#endif #endif
static void knife_input_ray_segment(KnifeTool_OpData *kcd, const int mval_i[2], const float ofs, static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2], const float ofs,
float r_origin[3], float r_origin_ofs[3]) float r_origin[3], float r_origin_ofs[3])
{ {
bglMats mats; bglMats mats;
float mval[2];
knife_bgl_get_mats(kcd, &mats); knife_bgl_get_mats(kcd, &mats);
mval[0] = (float)mval_i[0];
mval[1] = (float)mval_i[1];
/* unproject to find view ray */ /* unproject to find view ray */
ED_view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f); ED_view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f);
ED_view3d_unproject(&mats, r_origin_ofs, mval[0], mval[1], ofs); ED_view3d_unproject(&mats, r_origin_ofs, mval[0], mval[1], ofs);
@ -1483,7 +1480,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float
float ray[3]; float ray[3];
/* unproject to find view ray */ /* unproject to find view ray */
knife_input_ray_segment(kcd, kcd->vc.mval, 1.0f, origin, origin_ofs); knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
sub_v3_v3v3(ray, origin_ofs, origin); sub_v3_v3v3(ray, origin_ofs, origin);
f = BMBVH_RayCast(kcd->bmbvh, origin, ray, co, cageco); f = BMBVH_RayCast(kcd->bmbvh, origin, ray, co, cageco);
@ -1641,8 +1638,8 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo
/* update mouse coordinates to the snapped-to edge's screen coordinates /* update mouse coordinates to the snapped-to edge's screen coordinates
* this is important for angle snap, which uses the previous mouse position */ * this is important for angle snap, which uses the previous mouse position */
edgesnap = new_knife_vert(kcd, p, cagep); edgesnap = new_knife_vert(kcd, p, cagep);
kcd->curr.mval[0] = (int)edgesnap->sco[0]; kcd->curr.mval[0] = edgesnap->sco[0];
kcd->curr.mval[1] = (int)edgesnap->sco[1]; kcd->curr.mval[1] = edgesnap->sco[1];
} }
else { else {
@ -1720,8 +1717,8 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
/* update mouse coordinates to the snapped-to vertex's screen coordinates /* update mouse coordinates to the snapped-to vertex's screen coordinates
* this is important for angle snap, which uses the previous mouse position */ * this is important for angle snap, which uses the previous mouse position */
kcd->curr.mval[0] = (int)curv->sco[0]; kcd->curr.mval[0] = curv->sco[0];
kcd->curr.mval[1] = (int)curv->sco[1]; kcd->curr.mval[1] = curv->sco[1];
} }
return curv; return curv;
@ -1740,48 +1737,56 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
return NULL; return NULL;
} }
/* update both kcd->curr.mval and kcd->vc.mval to snap to required angle */
static void knife_snap_angle(KnifeTool_OpData *kcd) static void knife_snap_angle(KnifeTool_OpData *kcd)
{ {
int dx, dy; float dx, dy;
float w, abs_tan; float w, abs_tan;
dx = kcd->vc.mval[0] - kcd->prev.mval[0]; dx = kcd->curr.mval[0] - kcd->prev.mval[0];
dy = kcd->vc.mval[1] - kcd->prev.mval[1]; dy = kcd->curr.mval[1] - kcd->prev.mval[1];
if (dx == 0 || dy == 0) if (dx == 0.0f && dy == 0.0f)
return; return;
w = (float)dy / (float)dx; if (dx == 0.0f) {
kcd->angle_snapping = ANGLE_90;
kcd->curr.mval[0] =kcd->prev.mval[0];
}
w = dy / dx;
abs_tan = fabsf(w); abs_tan = fabsf(w);
if (abs_tan <= 0.4142f) { /* tan(22.5 degrees) = 0.4142 */ if (abs_tan <= 0.4142f) { /* tan(22.5 degrees) = 0.4142 */
kcd->angle_snapping = ANGLE_0; kcd->angle_snapping = ANGLE_0;
kcd->vc.mval[1] = kcd->prev.mval[1]; kcd->curr.mval[1] = kcd->prev.mval[1];
} }
else if (abs_tan < 2.4142f) { /* tan(67.5 degrees) = 2.4142 */ else if (abs_tan < 2.4142f) { /* tan(67.5 degrees) = 2.4142 */
if (w > 0) { if (w > 0) {
kcd->angle_snapping = ANGLE_45; kcd->angle_snapping = ANGLE_45;
kcd->vc.mval[1] = kcd->prev.mval[1] + dx; kcd->curr.mval[1] = kcd->prev.mval[1] + dx;
} }
else { else {
kcd->angle_snapping = ANGLE_135; kcd->angle_snapping = ANGLE_135;
kcd->vc.mval[1] = kcd->prev.mval[1] - dx; kcd->curr.mval[1] = kcd->prev.mval[1] - dx;
} }
} }
else { else {
kcd->angle_snapping = ANGLE_90; kcd->angle_snapping = ANGLE_90;
kcd->vc.mval[0] = kcd->prev.mval[0]; kcd->curr.mval[0] = kcd->prev.mval[0];
} }
kcd->vc.mval[0] = round_ftoi(kcd->curr.mval[0]);
kcd->vc.mval[1] = round_ftoi(kcd->curr.mval[1]);
} }
/* update active knife edge/vert pointers */ /* update active knife edge/vert pointers */
static int knife_update_active(KnifeTool_OpData *kcd) static int knife_update_active(KnifeTool_OpData *kcd)
{ {
knife_pos_data_clear(&kcd->curr);
kcd->curr.mval[0] = (float)kcd->vc.mval[0];
kcd->curr.mval[1] = (float)kcd->vc.mval[1];
if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING) if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING)
knife_snap_angle(kcd); knife_snap_angle(kcd);
knife_pos_data_clear(&kcd->curr);
kcd->curr.mval[0] = kcd->vc.mval[0];
kcd->curr.mval[1] = kcd->vc.mval[1];
/* XXX knife_snap_angle updates the view coordinate mouse values to constrained angles, /* XXX knife_snap_angle updates the view coordinate mouse values to constrained angles,
* which current mouse values are set to current mouse values are then used * which current mouse values are set to current mouse values are then used
* for vertex and edge snap detection, without regard to the exact angle constraint */ * for vertex and edge snap detection, without regard to the exact angle constraint */
@ -1799,7 +1804,7 @@ static int knife_update_active(KnifeTool_OpData *kcd)
float origin[3]; float origin[3];
float origin_ofs[3]; float origin_ofs[3];
knife_input_ray_segment(kcd, kcd->vc.mval, 1.0f, origin, origin_ofs); knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
closest_to_line_v3(kcd->curr.cage, kcd->prev.cage, origin_ofs, origin); closest_to_line_v3(kcd->curr.cage, kcd->prev.cage, origin_ofs, origin);
} }
@ -2929,11 +2934,11 @@ static void cage_mapped_verts_callback(void *userData, int index, const float co
} }
} }
static void knifetool_update_mval(KnifeTool_OpData *kcd, int mval[2]) static void knifetool_update_mval(KnifeTool_OpData *kcd, int mval_i[2])
{ {
knife_recalc_projmat(kcd); knife_recalc_projmat(kcd);
kcd->vc.mval[0] = mval[0]; kcd->vc.mval[0] = mval_i[0];
kcd->vc.mval[1] = mval[1]; kcd->vc.mval[1] = mval_i[1];
if (knife_update_active(kcd)) { if (knife_update_active(kcd)) {
ED_region_tag_redraw(kcd->ar); ED_region_tag_redraw(kcd->ar);