Phix / pGui Rosetta example : animate_pendulum2.exw

new topic     » topic index » view thread      » older message » newer message

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 
new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu