Phix / pGui Rosetta example : animate_pendulum2.exw
- Posted by lesterb Jul 05, 2018
- 1450 views
I had a look at this demo because there's a comment in the code about the pendulum going a bit mad when the window is being resized. I have indeed observed the madness and I believe I know why.
The pendulum position update and resize is done in the redraw callback (redraw_cb()) and this is activated by a canvas update requested by a call to IupDate() in the timer tick callback (timer_cb()).
Unfortunately, when the window is resized, redraw_cb() is also called by the system to repaint the screen. This means that while window resizing, the pendulum position update is called too often and the mad behaviour ensues. I measured up to 20 screen updates during resize rather than 1 or 2 normally.
So we need to repaint every update (to support resize/repaint) but only move the pendulum according to how many timer ticks there have been since last pendulum move.
I added a global variable 'tick' (to count timer ticks) and made small changes to redraw_cb() and timer_cb(). See code below.
The madness is much improved but there's another issue - by resizing the window up and down many times, it's possible to get the pendulum hurtling round the pivot point in one direction. The original code using both Arwen and pGui also displays this problem. Although amusing, it's probably not what's wanted.
My thought so far is that it's caused by the pendulum velocity being unrealistic for the new length but I haven't tried to fix it yet.
How important do you think this issue is?
-- Add after omega declaration atom ticks=0 -- Replace these 2 functions function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/) integer {w, h} = IupGetIntInt(canvas, "DRAWSIZE") cdCanvasActivate(cddbuffer) cdCanvasClear(cddbuffer) -- new suspension point and length integer sX = floor(w/2) integer sY = floor(h/8) integer len = sX-30 if ticks > 0 then -- only move if the timer has ticked (seems to be 0, 1 or 2) atom dt = 1/w/ticks -- divide 'dt' by number of ticks -- move: atom epsilon = -len*sin(alpha)*g omega += dt*epsilon alpha += dt*omega ticks=0 -- this tick count dealt with end if -- repaint: integer eX = floor(len*sin(alpha)+sX) integer eY = floor(len*cos(alpha)+sY) cdCanvasSetForeground(cddbuffer, CD_DARK_GREY) cdCanvasLine(cddbuffer, sX, h-sY, eX, h-eY) cdCanvasSetForeground(cddbuffer, CD_BLACK) cdCanvasSector(cddbuffer, eX, h-eY, 35, 35, 0, 360) cdCanvasFlush(cddbuffer) return IUP_DEFAULT end function function timer_cb(Ihandle /*ih*/) ticks += 1 IupUpdate(canvas) return IUP_IGNORE end function