Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Trickey <howard.trickey@gmail.com>2012-01-04 17:43:40 +0400
committerHoward Trickey <howard.trickey@gmail.com>2012-01-04 17:43:40 +0400
commit46b1ad99d390a5f2f3b670a67bd62f37987846b5 (patch)
treed06e0fd92f9437c58f460215419eff1279a03d48 /source/blender/editors/mesh/knifetool.c
parente2e5cb881c3a687ece844684be9c2bc5b253e57c (diff)
Add ability to constrain knife cut angle to 0, 45, or 90 degrees
Notes: - uses 'c' as toggle key in and out of angle snapping (aka constrain) mode - when in angle snapping mode, after first click, will constrain line to nears 0, 45, or 90 degree line - constraint is in screen space, not model space, so will usually be used in axis aligned view
Diffstat (limited to 'source/blender/editors/mesh/knifetool.c')
-rwxr-xr-xsource/blender/editors/mesh/knifetool.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/source/blender/editors/mesh/knifetool.c b/source/blender/editors/mesh/knifetool.c
index 0db0f5996ce..5133f921fba 100755
--- a/source/blender/editors/mesh/knifetool.c
+++ b/source/blender/editors/mesh/knifetool.c
@@ -181,7 +181,16 @@ typedef struct knifetool_opdata {
int snap_midpoints, prevmode, extend;
int ignore_edge_snapping, ignore_vert_snapping;
+ int prevmval[2];
+ enum {
+ ANGLE_FREE,
+ ANGLE_0,
+ ANGLE_45,
+ ANGLE_90,
+ ANGLE_135
+ } angle_snapping;
+
int is_space, prev_is_space; /*1 if current cut location, vertco, isn't on the mesh*/
float (*cagecos)[3];
} knifetool_opdata;
@@ -284,6 +293,8 @@ static void knife_start_cut(knifetool_opdata *kcd)
kcd->cutnr++;
kcd->prev_is_space = kcd->is_space;
kcd->is_space = 0;
+ kcd->prevmval[0] = kcd->vc.mval[0];
+ kcd->prevmval[1] = kcd->vc.mval[1];
copy_v3_v3(kcd->prevco, kcd->vertco);
copy_v3_v3(kcd->prevcage, kcd->vertcage);
@@ -507,6 +518,8 @@ static void knife_add_single_cut(knifetool_opdata *kcd)
copy_v3_v3(kcd->prevco, kcd->vertco);
copy_v3_v3(kcd->prevcage, kcd->vertcage);
kcd->prev_is_space = kcd->is_space;
+ kcd->prevmval[0] = kcd->vc.mval[0];
+ kcd->prevmval[1] = kcd->vc.mval[1];
}
static int verge_linehit(const void *vlh1, const void *vlh2)
@@ -687,6 +700,8 @@ static void knife_cut_through(knifetool_opdata *kcd)
copy_v3_v3(kcd->prevco, kcd->vertco);
copy_v3_v3(kcd->prevcage, kcd->vertcage);
kcd->prev_is_space = kcd->is_space;
+ kcd->prevmval[0] = kcd->vc.mval[0];
+ kcd->prevmval[1] = kcd->vc.mval[1];
}
static void knife_add_cut(knifetool_opdata *kcd)
@@ -770,6 +785,99 @@ static void knife_finish_cut(knifetool_opdata *UNUSED(kcd))
}
+static void knifetool_draw_angle_snapping(knifetool_opdata *kcd)
+{
+ bglMats mats;
+ double u[3], u1[2], u2[2], v1[3], v2[3], dx, dy;
+ double wminx, wminy, wmaxx, wmaxy;
+
+ /* make u the window coords of prevcage */
+ view3d_get_transformation(kcd->ar, kcd->vc.rv3d, kcd->ob, &mats);
+ gluProject(kcd->prevcage[0], kcd->prevcage[1], kcd->prevcage[2],
+ mats.modelview, mats.projection, mats.viewport,
+ &u[0], &u[1], &u[2]);
+
+ /* make u1, u2 the points on window going through u at snap angle */
+ wminx = kcd->ar->winrct.xmin;
+ wmaxx = kcd->ar->winrct.xmin + kcd->ar->winx;
+ wminy = kcd->ar->winrct.ymin;
+ wmaxy = kcd->ar->winrct.ymin + kcd->ar->winy;
+
+ switch (kcd->angle_snapping) {
+ case ANGLE_0:
+ u1[0] = wminx;
+ u2[0] = wmaxx;
+ u1[1] = u2[1] = u[1];
+ break;
+ case ANGLE_90:
+ u1[0] = u2[0] = u[0];
+ u1[1] = wminy;
+ u2[1] = wmaxy;
+ break;
+ case ANGLE_45:
+ /* clip against left or bottom */
+ dx = u[0] - wminx;
+ dy = u[1] - wminy;
+ if (dy > dx) {
+ u1[0] = wminx;
+ u1[1] = u[1] - dx;
+ } else {
+ u1[0] = u[0] - dy;
+ u1[1] = wminy;
+ }
+ /*clip against right or top */
+ dx = wmaxx - u[0];
+ dy = wmaxy - u[1];
+ if (dy > dx) {
+ u2[0] = wmaxx;
+ u2[1] = u[1] + dx;
+ } else {
+ u2[0] = u[0] + dy;
+ u2[1] = wmaxy;
+ }
+ break;
+ case ANGLE_135:
+ /* clip against right or bottom */
+ dx = wmaxx - u[0];
+ dy = u[1] - wminy;
+ if (dy > dx) {
+ u1[0] = wmaxx;
+ u1[1] = u[1] - dx;
+ } else {
+ u1[0] = u[0] + dy;
+ u1[1] = wminy;
+ }
+ /*clip against left or top */
+ dx = u[0] - wminx;
+ dy = wmaxy - u[1];
+ if (dy > dx) {
+ u2[0] = wminx;
+ u2[1] = u[1] + dx;
+ } else {
+ u2[0] = u[0] - dy;
+ u2[1] = wmaxy;
+ }
+ break;
+ default:
+ return;
+ }
+
+ /* unproject u1 and u2 back into object space */
+ gluUnProject(u1[0], u1[1], 0.0,
+ mats.modelview, mats.projection, mats.viewport,
+ &v1[0], &v1[1], &v1[2]);
+ gluUnProject(u2[0], u2[1], 0.0,
+ mats.modelview, mats.projection, mats.viewport,
+ &v2[0], &v2[1], &v2[2]);
+
+ glColor3f(0.6, 0.6, 0.6);
+ glLineWidth(2.0);
+ glBegin(GL_LINES);
+ glVertex3dv(v1);
+ glVertex3dv(v2);
+ glEnd();
+}
+
/* modal loop selection drawing callback */
static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
{
@@ -783,6 +891,9 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void
glMultMatrixf(kcd->ob->obmat);
if (kcd->mode == MODE_DRAGGING) {
+ if (kcd->angle_snapping != ANGLE_FREE)
+ knifetool_draw_angle_snapping(kcd);
+
glColor3f(0.1, 0.1, 0.1);
glLineWidth(2.0);
@@ -1439,9 +1550,41 @@ static KnifeVert *knife_find_closest_vert(knifetool_opdata *kcd, float p[3], flo
return NULL;
}
+static void knife_snap_angle(knifetool_opdata *kcd)
+{
+ int dx, dy;
+ float w, abs_tan;
+
+ dx = kcd->vc.mval[0] - kcd->prevmval[0];
+ dy = kcd->vc.mval[1] - kcd->prevmval[1];
+ if (dx == 0 || dy == 0)
+ return;
+
+ w = (float)dy / (float)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->prevmval[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->prevmval[1] + dx;
+ } else {
+ kcd->angle_snapping = ANGLE_135;
+ kcd->vc.mval[1] = kcd->prevmval[1] - dx;
+ }
+ } else {
+ kcd->angle_snapping = ANGLE_90;
+ kcd->vc.mval[0] = kcd->prevmval[0];
+ }
+}
+
/*update active knife edge/vert pointers*/
static int knife_update_active(knifetool_opdata *kcd)
{
+ if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING)
+ knife_snap_angle(kcd);
+
kcd->curvert = NULL; kcd->curedge = NULL; kcd->curbmface = NULL;
kcd->curvert = knife_find_closest_vert(kcd, kcd->vertco, kcd->vertcage, &kcd->curbmface, &kcd->is_space);
@@ -2003,6 +2146,7 @@ enum {
KNF_MODEL_IGNORE_SNAP_ON,
KNF_MODEL_IGNORE_SNAP_OFF,
KNF_MODAL_ADD_CUT,
+ KNF_MODAL_ANGLE_SNAP_TOGGLE
};
wmKeyMap* knifetool_modal_keymap(wmKeyConfig *keyconf)
@@ -2014,6 +2158,7 @@ wmKeyMap* knifetool_modal_keymap(wmKeyConfig *keyconf)
{KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap To Midpoints Off", ""},
{KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""},
{KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""},
+ {KNF_MODAL_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""},
{KNF_MODAL_NEW_CUT, "NEW_CUT", 0, "End Current Cut", ""},
{KNF_MODAL_ADD_CUT, "ADD_CUT", 0, "Add Cut", ""},
@@ -2044,6 +2189,8 @@ wmKeyMap* knifetool_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_PRESS, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_ON);
WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_RELEASE, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_OFF);
+ WM_modalkeymap_add_item(keymap, CKEY, KM_PRESS, 0, 0, KNF_MODAL_ANGLE_SNAP_TOGGLE);
+
WM_modalkeymap_assign(keymap, "MESH_OT_knifetool");
return keymap;
@@ -2109,6 +2256,9 @@ static int knifetool_modal (bContext *C, wmOperator *op, wmEvent *event)
ED_region_tag_redraw(kcd->ar);
kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 0;
break;
+ case KNF_MODAL_ANGLE_SNAP_TOGGLE:
+ kcd->angle_snapping = !kcd->angle_snapping;
+ break;
case KNF_MODAL_NEW_CUT:
ED_region_tag_redraw(kcd->ar);
knife_finish_cut(kcd);