From dc45169acde700470b7780327ae718b459558cab Mon Sep 17 00:00:00 2001 From: YimingWu Date: Mon, 14 Oct 2024 07:01:45 +0200 Subject: [PATCH] Fix #128637: Gizmo line tool not snapping to exactly 45 degrees Due to rounding errors in `wm_gesture_straightline_do_angle_snap`, it could give out a snapped result that's meant to be 45 degrees but does not have equal X/Y distances after converted to integer. Since 45 degrees can be used to make a equal length structure, it's best to make sure that resulting X/Y values are the same if the angle is multiple of 45 degrees. This fix would be effective for all tools that uses this "straight line gizmo". Pull Request: https://projects.blender.org/blender/blender/pulls/128683 --- .../windowmanager/intern/wm_gesture_ops.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.cc b/source/blender/windowmanager/intern/wm_gesture_ops.cc index 91c762fafbe..4ad5a619756 100644 --- a/source/blender/windowmanager/intern/wm_gesture_ops.cc +++ b/source/blender/windowmanager/intern/wm_gesture_ops.cc @@ -1052,6 +1052,22 @@ static void wm_gesture_straightline_do_angle_snap(rcti *rect, float snap_angle) rect->xmax = int(line_snapped_end[0]); rect->ymax = int(line_snapped_end[1]); + + /* Check whether `angle_snapped` is a multiple of 45 degrees, if so ensure X and Y directions + * are the same length (there could be an off-by-one due to rounding error). */ + const float fract_45 = fractf(angle_snapped / DEG2RADF(45.0f)); + const float fract_90 = fractf(angle_snapped / DEG2RADF(90.0f)); + /* Check if it's a multiple of 45 but not 90 degrees. */ + if ((compare_ff(fract_45, 0.0f, 1e-6) || compare_ff(fabsf(fract_45), 1.0f, 1e-6)) && + (!(compare_ff(fract_90, 0.0f, 1e-6) || compare_ff(fabsf(fract_90), 1.0f, 1e-6)))) + { + int xlen = abs(rect->xmax - rect->xmin); + int ylen = rect->ymax - rect->ymin; + if (abs(ylen) != xlen) { + ylen = xlen * (ylen >= 0 ? 1 : -1); + rect->ymax = rect->ymin + ylen; + } + } } int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *event)