Simple Harmonic Motion (string-mass system)
its nor 100%, but there's some motion already.
code not clean. idk if its really right.
/**
* Copyright Thy ( http://wonderfl.net/user/Thy )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/o5vy
*/
// its nor 100%, but there's some motion already.
// code not clean. idk if its really right.
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFormat;
/**
* ...
* @author Thi
*
* fórumlas do MHS (Movimento Harmônico Simples) e sistema massa-mola
* SHM formulas (Simple Harmonic Motion) and spring-mass system
* 数式は、(簡易高調波モーション)と 春の質量系 .. i guess ^^' (google transl)
*
* x = c (°) * 'x max' | x = x position
* 'x max' = r | r = amplitude
* (°) = °o + w * t | (°) = angle
* | °o = initial angle
* | t = time
* | c = cos
* v = -s (°) * 'v max' | v = x velocity
* 'v max' = w * r | s = sen
* w = 2 * pi / T | w = angular velocity
*
* a = -xw² | a = x acceleration
* T = 2 * pi * sqtr(m/k) | T = period
* | m = mass
* | k = spring constant
* | pi = 3.14...
* | sqtr = square root
* Fe = -kx | Fe = elastic Force
* Ee = kx²/2 | Ee = elastic Energy
* Ec = mv²/2 | Ec = cinetic Energy
*/
public class Main extends Sprite
{
private var
X:Number = 1, R:Number, ANG:Number, ANGO:Number = 0, t:Number = 0,
V:Number, W:Number,
ACC:Number, T:Number, M:Number = 1, K:Number = 1,
FE:Number, EE:Number, EC:Number;
// 1 meter is equal to 10 pixels
private var scale:Number = 100
// position x where the string have Fe = 0, and the cy
private var cx:Number = 465/2, cy:Number = 465/2
// mola (string), ball (body)
private var mola:Shape, ball:Shape
private var amplitude_circle:Shape
private var ang_ball:Shape
//
private var seta_X:Shape
private var seta_V:Shape
private var seta_ACC:Shape
//
private var drag:Boolean
// background
private var
back_data:BitmapData = new BitmapData(465, 465, false, 0xFFFFFF),
back_bitmap:Bitmap = new Bitmap(back_data, "auto", true)
// result variables (9 vars)
private var
r_ANG:TextField,
r_X:TextField, r_V:TextField, r_ACC:TextField,
r_T:TextField, r_W:TextField,
r_FE:TextField,
r_EE:TextField, r_EC:TextField
// input variables (5 vars)
private var
i_ANGO:TextField, i_R:TextField,
i_M:TextField, i_K:TextField,
i_SCALE:TextField
// temp
private var g:Graphics
private var i:int, j:int, k:int, l:int
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
//
stage.frameRate = 40
// shape init
shape_init()
// positions
ball.x = ang_ball.x = cx + X * scale
amplitude_circle.x = cx
mola.y = ball.y = amplitude_circle.y = ang_ball.y = cy
//
R = X
T = Math.sqrt(K / M)
W = 2 * Math.PI / T
// text init
text_init()
// childs
addChild(back_bitmap)
//
addChild(i_ANGO)
addChild(i_K)
addChild(i_M)
addChild(i_R)
addChild(i_SCALE)
addChild(r_ANG)
addChild(r_X)
addChild(r_V)
addChild(r_ACC)
addChild(r_T)
addChild(r_W)
addChild(r_FE)
addChild(r_EE)
addChild(r_EC)
//
addChild(mola) // w:115, h:10
addChild(amplitude_circle)
addChild(ang_ball)
addChild(ball) // w:11, h:11
//
addChild(seta_X)
addChild(seta_V)
addChild(seta_ACC)
//
mola.scaleX = (cx + X * scale) / cx // adjust scale (with ball position)
// listeners
stage.addEventListener(MouseEvent.MOUSE_DOWN, start_drag)
stage.addEventListener(Event.ENTER_FRAME, enter_frame)
stage.addEventListener(KeyboardEvent.KEY_DOWN, key_down)
}
private function shape_init():void
{
// mola (string)
var bend:int = 5
var step:Number = (cx - 15) / bend*.5
mola = new Shape()
g = mola.graphics
g.lineStyle(0)
g.lineTo(j = 5, k = 0)
i = -1
while (++i < bend)
{
g.lineTo(j += step, k - 5)
g.lineTo(j += step, k + 5)
}
g.lineTo(j += 5, k)
g.lineTo(j += 5, k)
// ball (body)
ball = new Shape()
g = ball.graphics
g.lineStyle(4, 0)
g.beginFill(0)
g.drawCircle(0, 0, 10)
g.endFill()
// amplitude circle
amplitude_circle = new Shape()
g = amplitude_circle.graphics
g.lineStyle(4, 0)
g.drawCircle(0, 0, X*scale)
// angle ball
ang_ball = new Shape()
g = ang_ball.graphics
g.lineStyle(4, 0)
g.beginFill(0xFFFFFF)
g.drawCircle(0, 0, 5)
g.endFill()
// setas (arrows)
seta_X = new Shape()
g = seta_X.graphics
g.lineStyle(4, 0xFF0000)
g.lineTo(100, 0)
seta_X.x = cx
seta_X.y = 400 - 30
//
seta_V = new Shape()
g = seta_V.graphics
g.lineStyle(4, 0x00FF00)
g.lineTo(100, 0)
seta_V.x = cx
seta_V.y = 400 - 20
//
seta_ACC = new Shape()
g = seta_ACC.graphics
g.lineStyle(4, 0x0000FF)
g.lineTo(100, 0)
seta_ACC.x = cx
seta_ACC.y = 400 - 10
}
private function text_init():void
{
i_ANGO = set_text(i_ANGO, true, 160)
i_K = set_text(i_K, true, 160)
i_M = set_text(i_M, true, 160)
i_R = set_text(i_R, true, 160)
i_SCALE = set_text(i_SCALE, true, 140)
i_ANGO.text = "°o ="
i_K.text = "k ="
i_M.text = "m ="
i_R.text = "A ="
i_SCALE.text = "scale ="
i_ANGO.x = 0
i_ANGO.y = 0
i_K.x = 0
i_K.y = 20
i_M.x = 0
i_M.y = 40
i_R.x = 210
i_R.y = 0
i_SCALE.x = 210
i_SCALE.y = 40
//
r_ANG = set_text(r_ANG, true, 110)
r_X = set_text(r_X, true, 110)
r_V = set_text(r_V, true, 110)
r_ACC = set_text(r_ACC, true, 110)
r_T = set_text(r_T, true, 110)
r_W = set_text(r_W, true, 110)
r_FE = set_text(r_FE, true, 110)
r_EE = set_text(r_EE, true, 110)
r_EC = set_text(r_EC, true, 110)
r_ANG.text = "° ="
r_X.text = "x ="
r_V.text = "v ="
r_ACC.text = "a ="
r_T.text = "T ="
r_W.text = "w ="
r_FE.text = "Fe ="
r_EE.text = "Ee ="
r_EC.text = "Ec ="
r_ANG.x = 140
r_X.x = 0
r_V.x = 0
r_ACC.x = 0
r_T.x = 140
r_W.x = 140
r_FE.x = 280
r_EE.x = 280
r_EC.x = 280
r_ANG.y = 400
r_X.y = 400
r_V.y = 420
r_ACC.y =440
r_T.y = 420
r_W.y = 440
r_FE.y = 400
r_EE.y = 420
r_EC.y = 440
//
r_X.textColor = 0xFF0000
r_V.textColor = 0x00FF00
r_ACC.textColor = 0x0000FF
//
back_data.draw(stage)
//
i_ANGO.text = String(ANGO)
i_K.text = String(K)
i_M.text = String(M)
i_R.text = String(R)
i_SCALE.text = String(scale)
i_ANGO.x = 40
i_ANGO.y = 0
i_K.x = 40
i_K.y = 20
i_M.x = 40
i_M.y = 40
i_R.x = 250
i_R.y = 0
i_SCALE.x = 270
i_SCALE.y = 40
i_ANGO.border = i_K.border = i_M.border = i_R.border = i_SCALE.border = true
//
r_ANG.x = 180
r_X.x = 30
r_V.x = 30
r_ACC.x = 30
r_T.x = 180
r_W.x = 180
r_FE.x = 320
r_EE.x = 320
r_EC.x = 320
//
r_X.textColor = 0
r_V.textColor = 0
r_ACC.textColor = 0
}
private function set_text(te:TextField, bool:Boolean = false, wid:Number = 0):TextField
{
if (te == null)
{
trace("nul")
te = new TextField()
}
var format:TextFormat = new TextFormat("Tahoma", 16)
te.defaultTextFormat = format
if (bool)
{
te.type = "input"
}
te.width = wid
te.height = 20
addChild(te)
return te
}
private function start_drag(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_DOWN, start_drag)
stage.removeEventListener(Event.ENTER_FRAME, enter_frame)
stage.addEventListener(MouseEvent.MOUSE_UP, stop_drag)
drag = true
//
if (mouseY > 60 && mouseY < 465)
{
mouse_move()
}
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouse_move)
}
private function stop_drag(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, stop_drag)
stage.addEventListener(MouseEvent.MOUSE_DOWN, start_drag)
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouse_move)
drag = false
//
ANG = 0
X = R
t = 0
stage.addEventListener(Event.ENTER_FRAME, enter_frame)
}
private var key_has_down:Boolean
private function key_down (e:KeyboardEvent):void
{
key_has_down = true
}
private function mouse_move(e:MouseEvent = null, bool:Boolean = false):void
{
if ((mouseY > 60 && mouseY < 465) || bool)
{
// update ball position
if (!bool)
{
R = (mouseX - cx) / scale
}
X = R
// circle amplitude
g = amplitude_circle.graphics
g.clear()
g.lineStyle(4, 0)
g.drawCircle(0, 0, R * scale)
//
ball.x = ang_ball.x = cx + X * scale
mola.scaleX = (cx + R * scale) / cx
ang_ball.y = cy
//
i_R.text = String(R)
}
}
private function enter_frame(e:Event):void
{
if (key_has_down) setup_input()
T = 2*Math.PI * Math.sqrt(M / K)
W = 2 * Math.PI / T
t -= 1/40 // flash angles are different from physics
ANG = -ANGO + W * t // angle, in radians already
//
X = Math.cos(ANG /** Math.PI / 180*/) * R // x position
V = Math.sin (ANG /** Math.PI/180*/) * W * R // x velocity
ACC = -X * W * W // x acceleration
//
FE = -K * X // elastic force
//
EE = K * X * X * .5 // elastic energy
EC = M * V * V * .5 // cinetic energy
// update movable shapes
screen_update()
// update texts
var sh:Shape = new Shape()
sh.rotation = (ANG) * 180 / Math.PI
if (sh.rotation < 0)
{
r_ANG.text = String(Math.round(-sh.rotation))
} else
{
r_ANG.text = String(Math.round(360 - sh.rotation))
}
//r_ANG.text = String(Math.round(sh.rotation))
r_X.text = String(Math.round(X * 100) / 100)
r_V.text = String(Math.round(V * 100) / 100);
r_ACC.text = String(Math.round(ACC * 1000)/1000)
r_T.text = String(Math.round(T*100)/100)
r_W.text = String(Math.round(W*100)/100)
r_FE.text = String(Math.round(FE*100)/100)
r_EE.text = String(Math.round(EE*100)/100)
r_EC.text = String(Math.round(EC*100)/100)
}
private function setup_input():void
{
key_has_down =false
ANGO = Number(i_ANGO.text) * Math.PI / 180
K = Number(i_K.text)
M = Number(i_M.text)
R = Number(i_R.text)
scale = Number(i_SCALE.text)
if(!Number(ANGO)) ANGO = 0
if(!Number(K)) K = 0
if(!Number(M)) M = 0
if(!Number(R)) R = 0
if (!Number(scale)) scale = 0.0001
//
mouse_move(null, true)
}
private function screen_update():void
{
ang_ball.x = cx + Math.cos(ANG /** Math.PI/180*/) * R * scale
ang_ball.y = cy + Math.sin(ANG /** Math.PI / 180*/) * R * scale
ball.x = cx + X * scale
mola.scaleX = (cx + X * scale) / cx
//
g = seta_X.graphics
g.clear()
g.lineStyle(4, 0xFF0000)
g.lineTo(X * scale, 0);
//
g = seta_V.graphics
g.clear()
g.lineStyle(4, 0x00FF00)
g.lineTo(V/W * scale, 0)
//
g = seta_ACC.graphics
g.clear()
g.lineStyle(4, 0x0000FF)
g.lineTo(ACC/(W*W) * scale, 0)
}
}
}