Point-Zoom on Mandelbrot Set in C# - It works, except when the mouse has moved -
i'm able point zoom on mandelbrot set, long mouse doesn't move after zooming has begun. i've tried calculating normalized delta (new coordinate - old coordinate)*(oldzoom), happens image appears jump around new location. i've seen issue before. i'm struggling more here because have somehow convert mouse position delta -2,2 coordinate space of mandelbrot set.
here's code. what's important getzoompoint method, , lines of code define x0 , y0. also, use range class scale values 1 range another. was using deltatrans (thats thing talking earlier normalize mouse delta old scale).
using opentk.graphics.opengl; using spritesheetmaker; using system; using system.collections.generic; using system.drawing; using system.linq; using system.text; using system.threading.tasks; namespace fractal.fractal { public class mandelbrot : basetexture { private static transform globaltransform = spritesheetmaker.global.transform; private static vector3 globalscale = globaltransform.scale; private static vector3 globaltrans = globaltransform.translation; private static vector3 lastwindowpoint = null; private static vector3 zoomfactor = vector3.one * 1.2f; private static vector3 displacement = vector3.zero; private static int windowsize = 100; public static vector3 getzoompoint() { var zp = openglhelpers.lastzoompoint.clone(); if (lastwindowpoint == null) { lastwindowpoint = zp.clone(); } var delta = zp - lastwindowpoint; var oldzoom = globalscale / zoomfactor; var deltatrans = delta.xy * oldzoom.xy; var factor = zoomfactor.clone(); range xr = new range(0, windowsize); range yr = new range(0, windowsize); range complexrange = new range(-2, 2); // calculate displacement of zooming position. var dx = (zp.x - displacement.x) * (factor.x - 1f); var dy = (zp.y - displacement.y) * (factor.y - 1f); // compensate displacement. displacement.x -= dx; displacement.y -= dy; zp -= displacement; var x = complexrange.scalevalue(zp.x, xr); var y = complexrange.scalevalue(zp.y, yr); var rtn = new vector3(x, y); lastwindowpoint = zp.clone(); return rtn; } public static mandelbrot generate() { var size = new size(windowsize, windowsize); var radius = new size(size.width / 2, size.height / 2); bitmap bmp = new bitmap(size.width, size.height); lockbitmap.lockbitmapunsafe lbm = new lockbitmap.lockbitmapunsafe(bmp); lbm.lockbits(); var pt = mandelbrot.getzoompoint(); parallel.for(0, size.width, => { // float x0 = complexrangex.scalevalue(i, xrange); float x0 = ((i - radius.width) / globalscale.x) + pt.x; parallel.for(0, size.height, j => { // float y0 = complexrangey.scalevalue(j, yrange); float y0 = ((j - radius.height) / globalscale.y) + pt.y; float value = 0f; float x = 0.0f; float y = 0.0f; int iteration = 0; int max_iteration = 100; while (x * x + y * y <= 4.0 && iteration < max_iteration) { float xtemp = x * x - y * y + x0; y = 2.0f * x * y + y0; x = xtemp; iteration += 1; if (iteration == max_iteration) { value = 255; break; } else { value = iteration * 50f % 255f; } } int v = (int)value; lbm.setpixel(i, j, new colorlibrary.hsl(v / 255f, 1.0, 0.5).todotnetcolor()); }); }); lbm.unlockbits(); var tex = new basetextureimage(bmp); var rtn = new mandelbrot(tex); return rtn; } public override void draw() { base._draw(); } private mandelbrot(basetextureimage graphic) { var topleft = new vector3(0, 1); var bottomleft = new vector3(0, 0); var bottomright = new vector3(1, 0); var topright = new vector3(1, 1); this.vertices = new list<vector3>() { topleft,bottomleft,bottomright,topright }; this.size.x = windowsize; this.size.y = windowsize; this.texture2d = graphic; } } }
i refactored code, , figured out solution problem. 2 big wins in one. ok, found solution on codeproject written in c# readily able adapt project. i'm not sure why didn't realize when posted question, needed solve issue create 'window' of zoom , not think in terms of 'point zoom'. yes, if trying zoom directly point, point center of sort of window.
here method have, expects start , end mousedown coordinates (screen space), , converts mandelbrot set window size accordingly.
public void applyzoom(double x0, double y0, double x1, double y1) { if (x1 == x0 && y0 == y1) { //this click, no movement occurred return; } /* * xmin, ymin , xmax, ymax current extent of set * mx0,my0 , mx1,my1 part selected * math draw selected rectangle * */ double scalex, scaley; scalex = (xmax - xmin) / (float)bitmapsize; scaley = (ymax - ymin) / (float)bitmapsize; xmax = (float)x1 * scalex + xmin; ymax = (float)y1 * scaley + ymin; xmin = (float)x0 * scalex + xmin; ymin = (float)y0 * scaley + ymin; this.refresh(); // force mandelbrot redraw }
basically, whats happening calculate ratio between mandelbrot window size versus screen size drawing to. then, using scale, convert our mousedown coordinates mandelbrot set coordinates (x1*scalex, etc) , manipulate current min , max coordinates them, using min values pivot point.
here's link codeproject used reference: codeproject link
Comments
Post a Comment