Murga-Projects Forums
someone with mad math skills, help please - Printable Version

+- Murga-Projects Forums (http://www.murga-projects.com/forum)
+-- Forum: Project Forums (/forumdisplay.php?fid=1)
+--- Forum: MurgaLua - General (/forumdisplay.php?fid=2)
+--- Thread: someone with mad math skills, help please (/showthread.php?tid=268)


someone with mad math skills, help please - mikshaw - 01-23-2008 09:39 AM

Actually, it's probably not mad skills needed, but I have next to none =o)

I've been messing around with a "gravity" test today, and although I came up with something cool to look at, it's not what I was trying for.

I can get the x,y position of the mouse, the x,y position of the object I want to move, and from there get the distance between the two points:
xdistance=math.abs(Fl:event_x()-object:x())
ydistance=math.abs(Fl:event_y()-object:y())
distance=math.sqrt(xdistance*xdistance+ydistance*ydistance)

What I would really like to do now is use that distance as a way to increase the motion of the object toward the mouse as the distance gets shorter. Essentially I'm looking for a single (floating point?) value that gradually increases as distance decreases. The problems I'm having are as follows:
1) I suck at math
2) The target speed should get larger as the distance gets smaller
3) The target speed should always be a fairly small non-negative number

Is there anyone who might be able to help?
Thanks.

This is the last thing I do before releasing the widgets-demo beta1


RE: someone with mad math skills, help please - Juergen - 01-23-2008 10:17 AM

If you want to have a linear dependency you could use something like that:

speed=v_min+a/(distance+c) where v_min is the minimal speed and v_min+a/c is the maximal speed. You need the c because for distance=0 the equation would become v_min+1/0 which does not work. So your c is c=a/(v_max - v_min)

Juergen


RE: someone with mad math skills, help please - mikshaw - 01-23-2008 11:25 AM

I only just read this, so haven't tried it yet, but I've already got "if distance > 0" before doing anything. I don't know if that makes it easier.

What is a?


RE: someone with mad math skills, help please - mikshaw - 01-23-2008 12:18 PM

I tried it assuming that 'a' was maximum speed, and came up with something different, but not very different than what I already had. Actually it was farther away from my goal.

Here is the curent loop I have, with this change:

Code:
function grav_loop()
local my_x,bx=Fl:event_x(),0
local my_y,by=Fl:event_y()-demo_bh,0
local c=math.random(1,255)
local b=math.random(1,balls)
ball[b]:color(c)
  for i=1,balls do
    local xdistance=math.abs(my_x-ball[i]:x())
    local ydistance=math.abs(my_y-ball[i]:y())
    local distance=math.sqrt(xdistance*xdistance+ydistance*ydistance)
    local speed=1+5/distance
    if distance > 0 then
      if my_x > ball[i]:x() then
        bx=ball[i]:x()+speed
      else
        bx=ball[i]:x()-speed
      end
      if my_y > ball[i]:y() then
        by=ball[i]:y()+speed
      else
        by=ball[i]:y()-speed
      end
      ball[i]:position(bx,by)
    end
  end
demo_widget:redraw()
grav_timer:doWait(.05)
end

ball is a table of randomly placed circles

EDIT: Actually I kinda like that one too. I'm going to keep it in the mix as stage 3. Thanks.


RE: someone with mad math skills, help please - mikshaw - 01-23-2008 12:41 PM

Holy crap! No, wait, it makes a HUGE difference just by changing the minimum and maximum to various values. This could keep me busy for a while.

Thank you Juergen! I think this is exactly what I was looking for.


RE: someone with mad math skills, help please - Juergen - 01-24-2008 08:01 AM

mikshaw Wrote:
Holy crap! No, wait, it makes a HUGE difference just by changing the minimum and maximum to various values. This could keep me busy for a while.

Thank you Juergen! I think this is exactly what I was looking for.


Of course this doesn't model gravitation. Gravitational forces go with 1/r^2.

If you want to make a simulation a N-body problem with randomly placed masses also is very problematic, because if you use fixed time steps (delta t) then the model will break because when 2 masses come very close the steps will be to big and when you select smaller dt then you won't see anything.

I can post an example in a few minutes.

Therefore it would make sense to simulate just a few bodies with a fixed setup (like a planetary system)

Juergen


RE: someone with mad math skills, help please - Juergen - 01-24-2008 08:31 AM

It might be possible to tweak it a little, so that it works better, but the main problem will prevail. Such a simple simulation won't work very good with so many bodies and a random initial setup. At least not if you want to see anything with a decent machine.

Juergen

P.S.: For some reason I can't attach it.

So here it is:

Code:
demo_widget:color(0)
balls=34
bsize=10

function grav_loop()
local planet_new={},g,m,r,sqr_r,rx,ry,m_j
time_step=max_slider:value()
  for i=1,balls do -- for every planet
    g={0,0}
    m=planet[i][1] -- with mass m
    for j=1,balls do -- with every other planet
      if i~=j then -- planets do not influence itself
        rx=planet[i][2]-planet[j][2]
        ry=planet[i][3]-planet[j][3]
        sqr_r=rx*rx+ry*ry
        r=math.sqrt(sqr_r) -- distance
        m_j=planet[j][1]  -- mass of the second planet
        g[1]=g[1]+(r>1 and m_j/sqr_r*rx/r or m_j*rx) -- gravitational field value (acceleration of the mass for time_step)
        g[2]=g[2]+(r>1 and m_j/sqr_r*ry/r or m_j*rx) -- of course a vector, we also don't want to use too small r values --> planets normally have a radius. Also r=0 is forbidden.
     end
    end
    g[1]=g[1]*grav_const -- we take to liberty to change the gravitational constant.
    g[2]=g[2]*grav_const -- not possible in real life!
    planet_new[i]={planet[i][1], -- the mass doesn't change
                   planet[i][2]+planet[i][4]*time_step+g[1]*time_step*time_step*.5, -- x_1=x_0+v_0*t+g/2*t^2 which is the new position of the object
                   planet[i][3]+planet[i][5]*time_step+g[2]*time_step*time_step*.5, -- the same
                   planet[i][4]+g[1]*time_step, -- v_1=v_0+g*t , which is the new speed of the object
                   planet[i][5]+g[2]*time_step} -- of course the same
    ball[i]:position(planet_new[i][2]/scale,planet_new[i][3]/scale)
  end
planet=planet_new -- everything starts from the beginning
demo_widget:redraw()
grav_timer:doWait(.05)
end





fltk.fl_define_FL_PLASTIC_UP_BOX()
math.randomseed(os.time())
scale=1000
max_x=(demo_widget:w()-bsize)*scale
max_y=(demo_widget:h()-bsize)*scale
max_m=20000000
min_m=1000000
max_ivx=50
max_ivy=50
grav_const=-1
ball={}

planet={}
for i=1,balls do
-- planets[i]={mass,pos_x,pos_y,v_x,v_y}
planet[i]={math.random(min_m,max_m),math.random(1,max_x),math.random(1,max_y),math.random(-max_ivx,max_ivx),math.random(-max_ivy,max_ivy)}
ball[i]=fltk:Fl_Box(planet[i][2]/scale,planet[i][3]/scale,bsize,bsize)
if fltk._FL_PLASTIC_ROUND_UP_BOX then ball[i]:box(fltk._FL_PLASTIC_ROUND_UP_BOX) else ball[i]:box(fltk.FL_PLASTIC_ROUND_UP_BOX) end
ball[i]:color(planet[i][1]/max_m*255)
end

max_slider=fltk:Fl_Hor_Value_Slider(0,demo_widget:h()-20,demo_widget:w(),20)
max_slider:minimum(1)
max_slider:maximum(100)
max_slider:value(.1)
max_slider:step(.1)

grav_timer = murgaLua.createFltkTimer()
grav_timer:callback(grav_loop)
grav_timer:do_callback()




RE: someone with mad math skills, help please - mikshaw - 01-24-2008 09:25 AM

I haven't looked at your script yet, but I've been messing around with various equations and come up with a handful of interesting pieces. Here's one that is cosest to my current goal:

Code:
balls=1500
bsize=2
min_grav=0
max_grav=6

function grav_loop()
local my_x,bx=Fl:event_x(),0
local my_y,by=Fl:event_y(),0
local c=math.random(1,255)
  for i=1,balls do
    local xdistance=math.abs(my_x-ball[i]:x())
    local ydistance=math.abs(my_y-ball[i]:y())
    local distance=math.sqrt(xdistance*xdistance+ydistance*ydistance)
    local xspeed=(min_grav+max_grav)/distance*xdistance
    local yspeed=(min_grav+max_grav)/distance*ydistance
    if distance <= 25 then
      ball[i]:color(c)
      -- need a better formula here
      xspeed=xspeed*max_x/distance*math.random(2,3)
      yspeed=yspeed*max_y/distance*math.random(2,3)
    end
    if my_x > ball[i]:x() then bx=ball[i]:x()+xspeed else bx=ball[i]:x()-xspeed end
    if my_y > ball[i]:y() then by=ball[i]:y()+yspeed else by=ball[i]:y()-yspeed end
    ball[i]:position(bx,by)
  end
w:redraw()
grav_timer:doWait(.05)
end

w=fltk:Fl_Double_Window(Fl:w(),Fl:h(),"gravity test")
w:color(0)

math.randomseed(os.time())
max_x=w:w()-bsize
max_y=w:h()-bsize
ball={}
for i=1,balls do
ball[i]=fltk:Fl_Box(math.random(1,max_x),math.random(1,max_y),bsize,bsize)
ball[i]:box(fltk.FL_FLAT_BOX)
end

grav_timer = murgaLua.createFltkTimer()
grav_timer:callback(grav_loop)
grav_timer:do_callback()

w:fullscreen()
w:show()
Fl:run()




RE: someone with mad math skills, help please - iGame3D - 01-24-2008 12:03 PM

ooh ahh thats so cool!
Comment that script, what a neat intro to murgaLua that makes!


RE: someone with mad math skills, help please - mikshaw - 01-25-2008 02:36 AM

I like this version best so far
EDIT: I think the warp equations might be in need of even more work. It looks fine on my 1024x768 resolution, but I think higher resolutions might end up with a lot of empty space.

Code:
balls=1500 -- number of dots
bsize=2    -- dot size
max_grav=6 -- maximum gravity
hole=20    -- distance from cursor within which dots warp

function grav_loop()
local my_x,my_y=Fl:event_x(),Fl:event_y() -- cursor location
local xspeed,yspeed,bx,by -- initialize some local vars
local c=math.random(1,255) -- random color (except black)
  for i=1,balls do
    -- find distance of dots from the cursor
    local xdistance=math.abs(my_x-ball[i]:x()) -- horz distance from cursor
    local ydistance=math.abs(my_y-ball[i]:y()) -- vert distance
    local distance=math.sqrt(xdistance^2+ydistance^2) -- as the crow flies
    if distance <= hole then
      ball[i]:color(c) -- set the color of the dot about to be warped
      -- These equations have no defined mathematical logic behind them.
      -- I was just playing with numbers until something cool happened.
      -- xspeed and yspeed are actually distance measurements (how far to move the dot in one loop)
      -- random offset prevents the dots from eventually converging on a single x-y intersection
      xspeed=distance*xdistance*2+math.random(-50,50)
      yspeed=distance*ydistance*2+math.random(-50,50)
    else
      -- thanks to Juergen for help with this
      xspeed=max_grav/distance*xdistance
      yspeed=max_grav/distance*ydistance
    end
    -- move the dot according to its relative position to cursor
    if my_x > ball[i]:x() then bx=ball[i]:x()+xspeed else bx=ball[i]:x()-xspeed end
    if my_y > ball[i]:y() then by=ball[i]:y()+yspeed else by=ball[i]:y()-yspeed end
    ball[i]:position(bx,by)
  end
w:redraw()
grav_timer:doWait(.05)
end

-- make the window the size of your screen
w=fltk:Fl_Double_Window(Fl:w(),Fl:h(),"gravity test")
w:color(0)

math.randomseed(os.time()) -- set a seed for upcoming math.random()
-- set up dots in random locations
ball={}
for i=1,balls do
ball[i]=fltk:Fl_Box(math.random(1,w:w()),math.random(1,w:h()),bsize,bsize)
ball[i]:box(fltk.FL_FLAT_BOX)
end

grav_timer = murgaLua.createFltkTimer()
grav_timer:callback(grav_loop)
grav_timer:do_callback()

w:fullscreen()
w:show()
w:cursor(66) -- cross
Fl:run()




RE: someone with mad math skills, help please - iGame3D - 01-25-2008 05:56 PM

Yep at 1440 x 900 it gets empty, then suddenly fills in all at once.

The second time it did this, most of the particles appeared in
two or three groups of blocks from the lower left side, instead
of a random all over the screen effect that the script starts with.


RE: someone with mad math skills, help please - mikshaw - 01-26-2008 02:38 AM

The grouping is intentional (although it often gets too dense) in order to display nebulae.
One of the other "features" of this is that there is a set number of dots. If you avoid coming into contact with them, they will eventually converge into one point. Touch that point and the dots are sprayed back on or outside the screen.

Still not satisfied with it, but I'm setting it aside for now to get back to some other projects.
I did make a change to hopefully spread the dots according to your screen size, and made that initial block of white dots blend in.

PHP Code:
balls=1500 -- number of dots
bsize
=2    -- dot size
max_grav
=-- maximum gravity
hole
=20    -- distance from cursor within which dots warp

function grav_loop()
local my_x,my_y=Fl:event_x(),Fl:event_y() -- cursor location
local xspeed
,yspeed,bx,by -- initialize some local vars
local c
=math.random(1,255) -- random color (except black)
  for 
i=1,balls do
    -- 
find distance of dots from the cursor
    local xdistance
=math.abs(my_x-ball[i]:x()) -- horz distance from cursor
    local ydistance
=math.abs(my_y-ball[i]:y()) -- vert distance
    local distance
=math.sqrt(xdistance^2+ydistance^2) -- as the crow flies
    
if distance <= hole then
      ball
[i]:color(c) -- set the color of the dot about to be warped
      
-- These equations have no defined mathematical logic behind them.
      -- 
I was just playing with numbers until something cool happened.
      -- 
xspeed and yspeed are actually distance measurements (how far to move the dot in one loop)
      -- 
random offset prevents the dots from eventually converging on a single x-y intersection
      xspeed
=xdistance*w:w()/distance/1.5+math.random(-100,100)
      
yspeed=ydistance*w:h()/distance/1.5+math.random(-100,100)
    else
      -- 
thanks to Juergen for help with this
      xspeed
=max_grav/distance*xdistance
      yspeed
=max_grav/distance*ydistance
    end
    
-- move the dot according to its relative position to cursor
    
if my_x ball[i]:x() then bx=ball[i]:x()+xspeed else bx=ball[i]:x()-xspeed end
    
if my_y ball[i]:y() then by=ball[i]:y()+yspeed else by=ball[i]:y()-yspeed end
    ball
[i]:position(bx,by)
  
end
w
:redraw()
grav_timer:doWait(.05)
end

-- make the window the size of your screen
w
=fltk:Fl_Double_Window(Fl:w(),Fl:h(),"gravity test")
w:color(0)

math.randomseed(os.time()) -- set a seed for upcoming math.random()
-- 
set up dots in random locations
ball
={}
for 
i=1,balls do
ball[i]=fltk:Fl_Box(math.random(-300,w:w()+600),math.random(-300,w:h()+600),bsize,bsize)
ball[i]:box(fltk.FL_FLAT_BOX)
ball[i]:color(math.random(1,255))
end

grav_timer 
murgaLua.createFltkTimer()
grav_timer:callback(grav_loop)
grav_timer:do_callback()

w:fullscreen()
w:show()
w:cursor(66) -- cross
Fl
:run()