diff --git a/solidify/overlap.c b/solidify/overlap.c index cebf03c..960fc47 100644 --- a/solidify/overlap.c +++ b/solidify/overlap.c @@ -362,24 +362,43 @@ static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, int dy = event->y-sy(s)/2; double r = hypot(dx, dy); double rc = r_center(s); + double rs, rot; int center = r < rc; int osd = osd_proximity(s, dx, dy); if (r < 1) return TRUE; + + /* + * rot goes exponentially from SLOWEST_ROT*rs to FASTEST_ROT for + * r = rc to rs, with rs being half the canvas diagonal. + * + * The values are picked such that we achieve sufficient precision at + * a reasonably large distance from the circle (for accidently entering + * the circle would change the mode) but can also spin quickly, e.g., + * when a 180 degrees rotation is needed. + * + * First, normalize to 0 ... 1 + * Then, we start at exp(0) and end at + * exp(ln(SLOWEST_ROT*rs/FASTEST_ROT))) + */ + rs = hypot(sx(s), sy(s))/2; + rot = (r-rc)/(rs-rc); + rot = SLOWEST_ROT*rs*exp(-rot*log(SLOWEST_ROT*rs/FASTEST_ROT)); + switch (event->direction) { case GDK_SCROLL_UP: if (center) shift(&s->a->m, dx, dy, 1); else - rotate(&s->a->m, dx > 0 ? r : -r); + rotate(&s->a->m, dx > 0 ? rot : -rot); draw_image(darea, s, osd); break; case GDK_SCROLL_DOWN: if (center) shift(&s->a->m, dx, dy, -1); else - rotate(&s->a->m, dx > 0 ? -r : r); + rotate(&s->a->m, dx > 0 ? -rot : rot); draw_image(darea, s, osd); break; default: diff --git a/solidify/style.h b/solidify/style.h index 14bb978..e678b15 100644 --- a/solidify/style.h +++ b/solidify/style.h @@ -23,6 +23,8 @@ extern GdkGC *gc_osd; #define LEVEL_CENTER_DIV 5 /* fraction of diagonal */ #define OVERLAP_BORDER 10 /* pixels around min. drawing area */ #define OVERLAP_CENTER_DIV 5 /* fraction of diagonal */ +#define SLOWEST_ROT 3 /* thrice the half-diagonal */ +#define FASTEST_ROT 2 /* one pixel in distance of 2 pixels */ void init_style(GdkDrawable *da);