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;
int is_space;
int mval[2]; /* mouse screen position */
float mval[2]; /* mouse screen position (may be non-integral if snapped to something) */
} KnifePosData;
/* 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);
#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]);
#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]);
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);
}
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])
{
@ -238,8 +242,8 @@ static void knife_pos_data_clear(KnifePosData *kpd)
kpd->vert = NULL;
kpd->edge = NULL;
kpd->bmface = NULL;
kpd->mval[0] = 0;
kpd->mval[1] = 0;
kpd->mval[0] = 0.0f;
kpd->mval[1] = 0.0f;
}
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] */
#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])
{
bglMats mats;
float mval[2], imat[3][3];
float imat[3][3];
knife_bgl_get_mats(kcd, &mats);
mval[0] = (float)mval_i[0];
mval[1] = (float)mval_i[1];
/* unproject to find view ray */
ED_view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f);
@ -1452,23 +1453,19 @@ static void knife_input_ray_cast(KnifeTool_OpData *kcd, const int mval_i[2],
}
#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])
{
bglMats mats;
float mval[2];
knife_bgl_get_mats(kcd, &mats);
mval[0] = (float)mval_i[0];
mval[1] = (float)mval_i[1];
/* unproject to find view ray */
ED_view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f);
ED_view3d_unproject(&mats, r_origin_ofs, mval[0], mval[1], ofs);
/* transform into object space */
invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
mul_m4_v3(kcd->ob->imat, r_origin);
mul_m4_v3(kcd->ob->imat, r_origin_ofs);
@ -1483,7 +1480,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float
float ray[3];
/* 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);
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
* this is important for angle snap, which uses the previous mouse position */
edgesnap = new_knife_vert(kcd, p, cagep);
kcd->curr.mval[0] = (int)edgesnap->sco[0];
kcd->curr.mval[1] = (int)edgesnap->sco[1];
kcd->curr.mval[0] = edgesnap->sco[0];
kcd->curr.mval[1] = edgesnap->sco[1];
}
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
* this is important for angle snap, which uses the previous mouse position */
kcd->curr.mval[0] = (int)curv->sco[0];
kcd->curr.mval[1] = (int)curv->sco[1];
kcd->curr.mval[0] = curv->sco[0];
kcd->curr.mval[1] = curv->sco[1];
}
return curv;
@ -1740,48 +1737,56 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
return NULL;
}
/* update both kcd->curr.mval and kcd->vc.mval to snap to required angle */
static void knife_snap_angle(KnifeTool_OpData *kcd)
{
int dx, dy;
float dx, dy;
float w, abs_tan;
dx = kcd->vc.mval[0] - kcd->prev.mval[0];
dy = kcd->vc.mval[1] - kcd->prev.mval[1];
if (dx == 0 || dy == 0)
dx = kcd->curr.mval[0] - kcd->prev.mval[0];
dy = kcd->curr.mval[1] - kcd->prev.mval[1];
if (dx == 0.0f && dy == 0.0f)
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);
if (abs_tan <= 0.4142f) { /* tan(22.5 degrees) = 0.4142 */
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 */
if (w > 0) {
kcd->angle_snapping = ANGLE_45;
kcd->vc.mval[1] = kcd->prev.mval[1] + dx;
kcd->curr.mval[1] = kcd->prev.mval[1] + dx;
}
else {
kcd->angle_snapping = ANGLE_135;
kcd->vc.mval[1] = kcd->prev.mval[1] - dx;
kcd->curr.mval[1] = kcd->prev.mval[1] - dx;
}
}
else {
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 */
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)
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,
* 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 */
@ -1799,7 +1804,7 @@ static int knife_update_active(KnifeTool_OpData *kcd)
float origin[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);
}
@ -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);
kcd->vc.mval[0] = mval[0];
kcd->vc.mval[1] = mval[1];
kcd->vc.mval[0] = mval_i[0];
kcd->vc.mval[1] = mval_i[1];
if (knife_update_active(kcd)) {
ED_region_tag_redraw(kcd->ar);