Gear
Gear simuration
/**
* Copyright flashrod ( http://wonderfl.net/user/flashrod )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/z44m
*/
// Gear simuration
package {
import flash.display.GradientType;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
public class Gear extends Sprite {
private static const area:Rectangle = new Rectangle(0, 0, 465, 465);
private var planes:Array = [];
private var torque:Object;
private var shafts:Array = [];
private var displays:Array = [];
public function Gear() {
rebuild();
stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {rebuild();});
addEventListener(Event.ENTER_FRAME, function(e:Event):void {
step();
for each (var o:Object in displays) {
o.shape.rotation = 180 * o.gear.angle / Math.PI;
}
});
}
private function put(a:Array, p:Object, g0:Object, n0:int):void {
if (n0 > 10) {
var m:int = 1 + 4 * Math.random();
var n:Array = [];
var sum:Number = 0;
for (var i:int = 0; i < m; ++i) {
var n2:int = n0 + n0 * Math.random();
n[i] = n2;
sum += n2;
}
var b:Array = [];
var a2:Number = 2 * Math.PI * Math.random();
for (i = 0; i < m; ++i) {
b[i] = (2 * Math.PI) * (a2 / sum);
a2 += n[i];
}
for (i = 0; i < m; ++i) {
var g2:Object = create_gear_mesh_with(g0, b[i], n[i]);
if (area.containsPoint(g2.center)) {
plane_add_gear(p, g2);
p.linkes.push({ tail:g0, head:g2 });
var s2:Shape = create_shape(g2, p.unit/4, Math.random() * 0xFFFFFF);
a.push({shape:s2, gear:g2});
put(a, p, g2, n0/2);
}
}
}
}
private function rebuild():void {
var a:Array = [];
var p1:Object = { unit:12, gears:[], linkes:[], table:[] };
p1.unit = 8 + 8 * Math.random();
planes.push(p1);
var n0:int = 30 + 30 * Math.random();
var p0:Point = new Point(area.width/2, area.height/2);
var g0:Object = create_gear(p0, n0);
plane_add_gear(p1, g0);
var s0:Shape = create_shape(g0, p1.unit/4, Math.random() * 0xFFFFFF);
a.push({shape:s0, gear:g0});
torque = g0;
put(a, p1, g0, n0);
var p2:Object = { unit:12, gears:[], linkes:[], table:[] };
p2.unit = p1.unit / 2;
planes.push(p2);
var g3:Object = a[int(Math.random() * a.length)].gear;
var n4:int = 30 + 30 * Math.random();
var p4:Point = g3.center;
var g4:Object = create_gear(p4, n4);
plane_add_gear(p2, g4);
shafts.push({ tail:g3, head:g4 });
var s4:Shape = create_shape(g4, p2.unit/4, Math.random() * 0xFFFFFF);
shape_plot_mark(s4, 8);
a.push({shape:s4, gear:g4});
put(a, p2, g4, n4);
for each (var o:Object in displays) {
removeChild(o.shape);
}
displays = a;
for each (o in displays) {
addChild(o.shape);
}
}
private function step():void {
for each (var p:Object in planes) {
plane_forEachGear(p, gear_begin);
}
gear_step(torque, 1/4);
for each (p in planes) {
plane_forEachGear(p, gear_commit);
}
}
private function plane_add_gear(plane:Object, g:Object):void {
g.parent = plane;
g.id = plane.gears.length;
plane.gears.push(g);
}
private function plane_get_links(plane:Object, g:Object):Array {
var a:Array = [];
for each (var link:Object in plane.linkes) {
if (link_contains(link, g)) {
a.push(link);
}
}
return a;
}
private function plane_links(plane:Object, g:Object):Array {
var a:Array = plane.table[g.id];
if (a == null) {
a = plane_get_links(plane, g);
plane.table[g.id] = a;
}
return a;
}
private function plane_get_shafts(g:Object):Array {
var a:Array = [];
for each (var link:Object in shafts) {
if (link_contains(link, g)) {
a.push(link);
}
}
return a;
}
private function plane_forEachGear(plane:Object, fn:Function):void {
for each (var g:Object in plane.gears) {
fn(g);
}
}
private function create_gear(c:Point, n:int, a:Number=0):Object {
return { parent:null, id:0, center: c, teeth: n, angle: a, next:0.0, visited:false };
}
private function create_gear_mesh_with(gear:Object, t:Number, n:Number):Object {
var p:Point = gear_meshPoint(gear, t, n);
var a:Number = gear_meshAngle(gear, t, n);
return create_gear(p, n, a);
}
private function gear_meshPoint(gear:Object, t:Number, n:Number):Point {
var r:Number = get_gear_radius(gear) + gear_toRadius(gear, n);
return new Point(gear.center.x + r * Math.cos(t), gear.center.y + r * Math.sin(t));
}
private function gear_meshAngle(gear:Object, t:Number, n:Number):Number {
var theta:Number = t - gear.angle;
var m:Number = gear_angleToTeeth(gear, get_gear_radius(gear), theta);
var phi:Number = gear_teethToAngle(gear, gear_toRadius(gear, n), m);
return Math.PI + (gear.angle) + (theta + phi);
}
private function gear_begin(gear:Object):void {
gear.visited = false;
gear.next = 0;
}
private function gear_commit(gear:Object):void {
gear.angle += gear.next * (2 * Math.PI / gear.teeth);
}
private function gear_step(gear:Object, v:Number):void {
if (!gear.visited) {
gear.visited = true;
gear.next = v;
for each (var link:Object in plane_links(gear.parent, gear)) {
var g:Object = link_other(link, gear);
gear_step(g, -v);
}
for each (link in plane_get_shafts(gear)) {
g = link_other(link, gear);
gear_step(g, gear_angleToTeeth(g, get_gear_radius(g), gear_teethToAngle(gear, get_gear_radius(gear), v)));
}
}
}
private function get_gear_radius(gear:Object):Number {
return gear_toRadius(gear, gear.teeth);
}
private function gear_angleToTeeth(gear:Object, r:Number, a:Number):Number {
return a * r / gear.parent.unit;
}
private function gear_teethToAngle(gear:Object, r:Number, n:Number):Number {
return n * gear.parent.unit / r;
}
private function gear_toRadius(gear:Object, n:Number):Number {
return n * gear.parent.unit / (2 * Math.PI);
}
private function create_shape(gear:Object, delta:Number=4, color:uint=0):Shape {
var shape:Shape = new Shape();
shape.x = gear.center.x;
shape.y = gear.center.y;
var r:int = get_gear_radius(gear);
var teeth:int = gear.teeth;
shape.graphics.lineStyle(1, color);
shape.graphics.moveTo(r, 0);
shape.graphics.beginGradientFill(GradientType.LINEAR, [color, color], [0, 1], [0, 255]);
shape.graphics.lineStyle(0, color);
var m1:Matrix = new Matrix();
m1.rotate(-60 * 2 * Math.PI / 360);
var m2:Matrix = new Matrix();
m2.rotate(60 * 2 * Math.PI / 360);
for (var t:int = 0; t < teeth; ++t) {
var a1:Number = 2 * Math.PI * t/teeth;
var a3:Number = 2 * Math.PI * (t+1)/teeth;
var a2:Number = (a1 + a3) / 2;
var p1:Point = new Point(r * Math.cos(a1), r * Math.sin(a1));
var p2:Point = new Point(r * Math.cos(a2), r * Math.sin(a2));
var p3:Point = new Point(r * Math.cos(a3), r * Math.sin(a3));
var v12:Point = p2.subtract(p1);
v12.normalize(delta);
var q12:Point = p1.add(m1.transformPoint(v12));
var v21:Point = p1.subtract(p2);
v21.normalize(delta);
var q21:Point = p2.add(m2.transformPoint(v21));
shape.graphics.lineTo(q12.x, q12.y);
shape.graphics.lineTo(q21.x, q21.y);
shape.graphics.lineTo(p2.x, p2.y);
var v23:Point = p3.subtract(p2);
v23.normalize(delta);
var q23:Point = p2.add(m2.transformPoint(v23));
var v32:Point = p2.subtract(p3);
v32.normalize(delta);
var q32:Point = p3.add(m1.transformPoint(v32));
shape.graphics.lineTo(q23.x, q23.y);
shape.graphics.lineTo(q32.x, q32.y);
shape.graphics.lineTo(p3.x, p3.y);
}
shape.graphics.endFill();
return shape;
}
private function shape_plot_mark(shape:Shape, d:int):void {
shape.graphics.drawCircle(0, 0, d);
shape.graphics.moveTo(0, d);
shape.graphics.lineTo(0, -d);
shape.graphics.moveTo(d, 0);
shape.graphics.lineTo(-d, 0);
}
private function link_contains(link:Object, g:Object):Boolean {
return g == link.tail || g == link.head;
}
private function link_other(link:Object, g:Object):Object {
return g == link.tail ? link.head : g == link.head ? link.tail : null;
}
}
}