Skip to content

Instantly share code, notes, and snippets.

@vurtun
Last active January 7, 2020 14:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vurtun/c62c75e0fe824c3dfa58dcb744a6a4ca to your computer and use it in GitHub Desktop.
Save vurtun/c62c75e0fe824c3dfa58dcb744a6a4ca to your computer and use it in GitHub Desktop.
Zoom to point
static float
scalbnf(float x, int n)
{
union {float f; unsigned i;} u;
float y = x;
if (n > 127) {
y *= 0x1p127f;
n -= 127;
if (n > 127) {
y *= 0x1p127f;
n -= 127;
if (n > 127)
n = 127;
}
} else if (n < -126) {
y *= 0x1p-126f * 0x1p24f;
n += 126 - 24;
if (n < -126) {
y *= 0x1p-126f * 0x1p24f;
n += 126 - 24;
if (n < -126)
n = -126;
}
}
u.i = (unsigned)(0x7f+n)<<23;
x = y * u.f;
return x;
}
static float
expf(float x)
{
static const float half[2] = {0.5,-0.5};
static const float ln2hi = 6.9314575195e-1f; /* 0x3f317200 */
static const float n2lo = 1.4286067653e-6f; /* 0x35bfbe8e */
static const float invln2 = 1.4426950216e+0f; /* 0x3fb8aa3b */
/*
* Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]:
* |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74
*/
static const float P1 = 1.6666625440e-1f; /* 0xaaaa8f.0p-26 */
static const float P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */
float hi, lo, c, xx, y;
int k, sign;
unsigned hx;
union {float f; unsigned i;} u;
u.f = x; hx = u.i;
sign = hx >> 31; /* sign bit of x */
hx &= 0x7fffffff; /* high word of |x| */
/* special cases */
if (hx >= 0x42aeac50) { /* if |x| >= -87.33655f or NaN */
if (hx > 0x7f800000) /* NaN */
return x;
if (hx >= 0x42b17218 && !sign) { /* x >= 88.722839f */
/* overflow */
x *= 0x1p127f;
return x;
}
if (sign) {
/* underflow */
volatile float __x = -0x1p-149f/x;
if (hx >= 0x42cff1b5) /* x <= -103.972084f */
return 0;
}
}
/* argument reduction */
if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */
k = invln2*x + half[sign];
else
k = 1 - sign - sign;
hi = x - k*ln2hi; /* k*ln2hi is exact here */
lo = k*ln2lo;
x = hi - lo;
} else if (hx > 0x39000000) { /* |x| > 2**-14 */
k = 0;
hi = x;
lo = 0;
} else {
/* raise inexact */
volatile float __x = 0x1p127f + x;
return 1 + x;
}
/* x is now in primary range */
xx = x*x;
c = x - xx*(P1+xx*P2);
y = 1 + (x*c/(2-c) - lo + hi);
if (k == 0) return y;
return scalbnf(y, k);
}
static void
pnt_view_to_img(float *out, const float *pnt,
float scaler, const float *off)
{
out[0] = (pnt[0]+off[0])/scaler;
out[1] = (pnt[1]+off[1])/scaler;
}
static void
zoom_to_pnt_off(float *off, const float *pnt,
float old_scaler, float new_scaler)
{
float img_pnt[2];
pnt_view_to_img(img_pnt, pnt, old_scaler, off);
off[0] = (img_pnt[0]*new_scaler)-pnt[0];
off[1] = (img_pnt[1]*new_scaler)-pnt[1];
}
int main(int argc, char **argv)
{
static const float zoom_fak = 0.2f;
float off[2] = {0};
float zoom = 0.0f;
float scale = 1.0f; // expf(zoom);
// ...
{
// mouse scroll handler
zoom += scrl_wheel * zoom_fak;
const float new_scale = expf(zoom);
zoom_to_pnt_off(off, view_rel_mouse_pos, scale, new_scale);
scale = new_scale;
}
// ...
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment