| View.Set ("offscreenonly,graphics:600;600,nobuttonbar")
 type Point :
 record
 x, y : real
 end record
 
 fcn closestPoint (p1, p2, p3 : Point) : Point
 var ret : Point
 var u : real := ((p3.x - p1.x) * (p2.x - p1.x) + (p3.y - p1.y) * (p2.y - p1.y)) / Math.Distance (p1.x, p1.y, p2.x, p2.y) ** 2
 ret.x := p1.x + u * (p2.x - p1.x)
 ret.y := p1.y + u * (p2.y - p1.y)
 if ret.x < min (p1.x, p2.x) then
 if p1.x < p2.x then
 ret := p1
 else
 ret := p2
 end if
 elsif ret.x > max (p1.x, p2.x) then
 if p1.x > p2.x then
 ret := p1
 else
 ret := p2
 end if
 end if
 result ret
 end closestPoint
 
 fcn dist (p1, p2 : Point) : real
 result Math.Distance (p1.x, p1.y, p2.x, p2.y)
 end dist
 
 fcn whatAngle (x1, y1, x2, y2 : real) : real
 var dx, dy, ratio, angle : real
 dx := x2 - x1
 dy := y2 - y1
 if dx not= 0 then
 ratio := dy / dx
 else
 ratio := dy / 0.00001
 end if
 angle := arctand (abs (ratio))
 if dx < 0 then
 angle := 180 - angle
 end if
 if dy < 0 then
 angle := 360 - angle
 end if
 result round (angle)
 end whatAngle
 
 proc drawLine (p1, p2 : Point)
 Draw.Line (round (p1.x), round (p1.y), round (p2.x), round (p2.y), black)
 Draw.FillOval (round (p1.x), round (p1.y), 3, 3, white)
 Draw.Oval (round (p1.x), round (p1.y), 3, 3, black)
 Draw.FillOval (round (p2.x), round (p2.y), 3, 3, white)
 Draw.Oval (round (p2.x), round (p2.y), 3, 3, black)
 end drawLine
 
 const POINTS := 8
 const RADIUS := 20
 const GRAVITY := 0.001
 
 var points : array 1 .. POINTS of Point
 for i : 1 .. POINTS
 %points (i).y := Rand.Int (maxy div 2 - 10, maxy div 2 + 10) - 100
 %points (i).x := (maxx / (POINTS - 1)) * (i - 1)
 points (i).x := cosd ((-i + 1) * (180 / (POINTS - 1))) * (maxx div 2) + maxx div 2
 points (i).y := sind ((-i + 1) * (180 / (POINTS - 1))) * (maxx div 2) + maxy div 2
 end for
 
 var p, d, V, P, Z : Point
 var vx, vy, angle, mag, s : real := 0
 p.x := maxx
 p.y := maxy div 2 + 50
 Z.x := 0
 Z.y := 0
 vx := -0.3
 
 loop
 for i : 1 .. POINTS - 1
 drawLine (points (i), points (i + 1))
 Draw.Oval (round (p.x), round (p.y), RADIUS, RADIUS, black)
 d := closestPoint (points (i), points (i + 1), p)
 if dist (p, d) <= RADIUS then
 s := Math.Distance (0, 0, vx, vy)
 
 angle := whatAngle (0, 0, -vx, -vy) - (whatAngle (points (i + 1).x, points (i + 1).y, points (i).x, points (i).y) + 90)
 angle := (whatAngle (points (i + 1).x, points (i + 1).y, points (i).x, points (i).y) + 90) - angle
 
 vx := cosd (angle) * s
 vy := sind (angle) * s
 end if
 %drawLine (p, closestPoint (points (i), points (i + 1), p))
 end for
 
 if p.x <= RADIUS| p.x >= maxx - RADIUS then
 p.x := max (RADIUS, min (maxx - RADIUS, p.x))
 vx *= -1
 elsif p.y >= maxy - RADIUS then
 p.x := maxy - RADIUS
 vy *= -1
 end if
 
 p.x += vx
 p.y += vy
 vy -= GRAVITY
 
 locate (1, 1)
 put "X: ", p.x, " Y: ", p.y
 put "VX: ", vx, " VY: ", vy
 put angle
 
 View.Update
 cls
 end loop
 |