# Copyright (C) 2004-2005 Kouichirou Eto, All rights reserved.
$LOAD_PATH.unshift("..") if !$LOAD_PATH.include?("..")
module SGL
# not yet.
module SpringModule
end
class Spring
EPSILON = 0.01
# ڕWƂȂlAlAol萔Ae萔ACvV(\l)
def initialize(target, initial, ks, kd, e=EPSILON, v=0)
@target, @initial, @ks, @kd, @e, @v = target, initial, ks, kd, e, v
@x = @initial
@moving = true
end
attr_reader :x, :target
attr_accessor :v, :ks, :kd
def inspect
mov = @moving ? "" : ""
sprintf("[%s%.1f %.1f %.1f %.1f %.1f]", mov, @target, @x, @v, @ks, @kd)
end
def target=(num)
@target = num
@moving = true
end
def x=(num)
@x = num
@moving = true
end
def move
return if ! @moving
if @x.is_a?(Vector)
l = @x - @target
diff = l.length
if diff < @e && @v.length < @e
@moving = false
return
end
#fa = -(@ks * diff + @kd * @v)
ln = l.normalize
fak = -(@ks * diff + @kd * @v.length)
fa = ln.scale(fak)
@v += fa
@x += @v
#p ['sp', fa, fak, @v, @x]
else
diff = @x - @target
if diff.abs < @e && @v.abs < @e
@moving = false
return
end
fa = -(@ks * diff + @kd * @v)
@v += fa
@x += @v
end
end
end
class ISpring < Spring
# ڕWƂȂlAlAol萔Ae萔ACvV(\l)
def initialize(target, initial, ks, kd, e=EPSILON, v=0)
super(target, initial, 1.0/ks, 1.0/kd, e, v) # kskdinverseB
end
end
class NumSpring
EPSILON = 0.01
# ڕWƂȂlAlAol萔Ae萔ACvV(\l)
def initialize(target, initial, ks, kd, e=EPSILON, v=0)
@target, @initial, @ks, @kd, @e, @v = target, initial, ks, kd, e, v
@x = @initial
@moving = true
end
attr_reader :x, :target
attr_accessor :v, :ks, :kd, :moving
def inspect
mov = @moving ? "" : ""
sprintf("[%s%.1f %.1f %.1f %.1f %.1f]", mov, @target, @x, @v, @ks, @kd)
end
def target=(num)
@target = num
@moving = true
end
def x=(num)
@x = num
@moving = true
end
def move
return if ! @moving
diff = @target - @x
if diff.abs < @e && @v.abs < @e
@moving = false
return
end
@v += (diff / @ks)
@v *= @kd
@x += @v
end
end
class INumSpring < NumSpring
# ڕWƂȂlAlAol萔Ae萔ACvV(\l)
def initialize(target, initial, ks, kd, e=EPSILON, v=0)
super(target, initial, ks, 1.0 - 1.0/kd, e, v) # kdinverseB
end
end
end
class NuSpringPos
EPSILON = 0.01
# lAڕWƂȂlAol萔Ae萔ACvV(\l)
def initialize(x, y, ks, kd, e=EPSILON)
@x, @y, @ks, @kd, @e = x, y, ks, kd, e
@vx, @vy, @tx, @ty = 0, 0, 0, 0
@moving = true
end
attr_reader :x, :y, :moving
def set_target(tx, ty)
@tx, @ty = tx, ty
end
def move
return if ! @moving
#diff = @target - @x
diff = @tx - @x
if diff.abs < @e && @v.abs < @e
@moving = false
return
end
@v += (diff / @ks)
@v *= @kd
@x += @v
end
end
class NuNumSpring
EPSILON = 0.01
# ڕWƂȂlAlAol萔Ae萔ACvV(\l)
def initialize(target, initial, ks, kd, e=EPSILON)
@target, @initial, @ks, @kd, @e = target, initial, ks, kd, e
@x = @initial
@v = 0
@moving = true
end
attr_reader :v
attr_accessor :x, :target, :moving, :ks, :kd
def inspect
mov = @moving ? "" : ""
sprintf("[%s%.1f %.1f %.1f %.1f %.1f]", mov, @target, @x, @v, @ks, @kd)
end
def move
return if ! @moving
diff = @target - @x
if diff.abs < @e && @v.abs < @e
@moving = false
return
end
@v += (diff / @ks)
@v *= @kd
@x += @v
end
def rel_ks_notuse(r)
@ks += r
@ks = 1 if @ks <= 0
end
end
if $0 == __FILE__
require "test/unit"
$test = true
end
if defined?($test) && $test
class TestSglSpring < Test::Unit::TestCase
def test_all
s = SGL::NumSpring.new(0, 1, 0.1, 0.1)
assert_equal(1, s.x)
assert_equal(true, s.moving)
s.move
assert_equal(0.0, s.x)
s.move
assert_equal(-0.1, s.x)
end
end
end
83