In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Catenary

参考
http://www.mathhelpforum.com/math-help/f6/catenary-cable-different-heights-96398.html
/**
 * Copyright poiasd ( http://wonderfl.net/user/poiasd )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/8Bnl
 */

package {
    
    import flash.display.Graphics;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    
    [SWF (width = "465", height = "465", frameRate = "30", backgroundColor = "0xFFFFFF")]
    
    public class Main extends Sprite {
        
        private const _EPSILON:Number = 1e-6;
        private const _LENGTH:Number = 400;
        private const _SEGMENTS:uint = 20;
        
        private var _stageWidth:int;
        private var _stageHeight:int;
        private var _canvas:Shape;
        private var _target:Handle = null;
        private var _offset:Point = new Point();
        private var _handle1:Handle;
        private var _handle2:Handle;
        private var _distance:Number;
        
        public function Main() {
            _init();
        }
        
        private function _init():void {
            stage.scaleMode = "noScale";
            stage.align = "TL";
            _stageWidth = stage.stageWidth;
            _stageHeight = stage.stageHeight;
            
            graphics.beginFill(0x111111);
            graphics.drawRect(0, 0, _stageWidth, _stageHeight);
            graphics.endFill();
            
            _canvas = addChild(new Shape()) as Shape;
            
            _handle1 = addChild(new Handle((_stageWidth >> 1) - 125, 100)) as Handle;
            _handle2 = addChild(new Handle((_stageWidth >> 1) + 125, 100)) as Handle;
            _handle1.target = _handle2;
            _handle2.target = _handle1;
            _distance = Point.distance(_handle1.position, _handle2.position);
            
            stage.addEventListener(MouseEvent.MOUSE_DOWN, _mouseDownHandler);
            stage.addEventListener(MouseEvent.MOUSE_UP, _mouseUpHandler);
            _update();
        }
        
        private function _mouseDownHandler(event:MouseEvent):void {
            if (event.target.name == "handle") {
                _target = event.target as Handle;
                _offset.x = _target.x - stage.mouseX;
                _offset.y = _target.y - stage.mouseY;
                stage.addEventListener(MouseEvent.MOUSE_MOVE, _mouseMoveHandler);
            }
        }
        
        private function _mouseMoveHandler(event:MouseEvent):void {
            var h1:Handle = _target;
            var h2:Handle = _target.target;
            h1.x = stage.mouseX + _offset.x;
            h1.y = stage.mouseY + _offset.y;
            var dx:Number = h2.x - h1.x;
            var dy:Number = h2.y - h1.y;
            _distance = Math.sqrt(dx * dx + dy * dy);
            if (_distance > _LENGTH) {
                h1.x = h2.x - _LENGTH * dx / _distance;
                h1.y = h2.y - _LENGTH * dy / _distance;
                _distance = _LENGTH;
            }
            _update();
            event.updateAfterEvent();
        }
        
        private function _mouseUpHandler(event:MouseEvent):void {
            if (_target) {
                _target = null;
                stage.removeEventListener(MouseEvent.MOUSE_MOVE, _mouseMoveHandler);
            }
        }
        
        private function _update():void {
            var p1:Point = _handle1.position;
            var p2:Point = _handle2.position;
            if (p1.x > p2.x) {
                var temp:Point = p1;
                p1 = p2;
                p2 = temp;
            }
            var g:Graphics = _canvas.graphics;
            g.clear();
            g.lineStyle(1, 0xFFFFFF, 0.8);
            if (_distance < _LENGTH) {
                if (p2.x - p1.x > 0.01) {
                    var d:Number = p2.x - p1.x;
                    var h:Number = p2.y - p1.y;
                    var a:Number = -_getCatenaryParameter(d, h, _LENGTH);
                    var x:Number = (a * Math.log((_LENGTH + h) / (_LENGTH - h)) - d) * 0.5;
                    var y:Number = a * _cosh(x / a);
                    var offsetX:Number = p1.x - x;
                    var offsetY:Number = p1.y - y;
                    _drawCatenary(a, p1, p2, offsetX, offsetY);
                } else {
                    var mx:Number = (p1.x + p2.x) * 0.5;
                    var my:Number = (p1.y + p2.y + _LENGTH) * 0.5;
                    g.moveTo(p1.x, p1.y);
                    g.lineTo(mx, my);
                    g.lineTo(p2.x, p2.y);
                }
            } else {
                g.moveTo(p1.x, p1.y);
                g.lineTo(p2.x, p2.y);
            }
        }
        
        private function _getCatenaryParameter(d:Number, h:Number, length:Number):Number {
            var m:Number = Math.sqrt(length * length - h * h) / d;
            var x:Number = _acosh(m) + 1;
            var prevx:Number = -1;
            var count:int = 0;
            while (Math.abs(x - prevx) > _EPSILON && count < 100) {
                prevx = x;
                x = x - (_sinh(x) - m * x) / (_cosh(x) - m);
                count++;
            }
            return d / (2 * x);
        }
        
        private function _drawCatenary(a:Number, p1:Point, p2:Point, offsetX:Number, offsetY:Number):void {
            var data:Array = [p1.x, a * _cosh((p1.x - offsetX) / a) + offsetY];
            var d:Number = p2.x - p1.x;
            var length:int = _SEGMENTS - 1;
            for (var i:int = 0; i < length; i++) {
                var x:Number = p1.x + d * (i + 0.5) / length;
                var y:Number = a * _cosh((x - offsetX) / a) + offsetY;
                data.push(x, y);
            }
            data.push(p2.x, a * _cosh((p2.x - offsetX) / a) + offsetY);
            SmoothCurve.draw(_canvas.graphics, data);
        }
        
        private function _sinh(x:Number):Number {
            return (Math.exp(x) - Math.exp(-x)) * 0.5;
        }
        
        private function _cosh(x:Number):Number {
            return (Math.exp(x) + Math.exp(-x)) * 0.5;
        }
        
        private function _acosh(x:Number):Number {
            return Math.log(x + Math.sqrt(x * x - 1));
        }
        
    }
    
}

import flash.display.Graphics;
import flash.display.Sprite;
import flash.geom.Point;

class Handle extends Sprite {
    
    public var target:Handle;
    
    public function Handle(x:Number = 0, y:Number = 0) {
        graphics.beginFill(0xF69824, 0.3);
        graphics.drawCircle(0, 0, 6);
        graphics.beginFill(0xF6C824, 0.8);
        graphics.drawCircle(0, 0, 2);
        graphics.endFill();
        this.x = x;
        this.y = y;
        name = "handle";
        buttonMode = true;
    }
    
    public function get position():Point {
        return new Point(x, y);
    }
    
}

class SmoothCurve {
    
    public static function draw(canvas:Graphics, data:Array):void {
        var length:int = data.length * 0.5 - 1;
        var ox:Number = data[2];
        var oy:Number = data[3];
        canvas.moveTo(data[0], data[1]);
        for (var i:int = 2; i < length; i++) {
            var x:Number = data[i * 2];
            var y:Number = data[i * 2 + 1];
            var mx:Number = (x + ox) * 0.5;
            var my:Number = (y + oy) * 0.5;
            canvas.curveTo(ox, oy, mx, my);
            ox = x;
            oy = y;
        }
        length = data.length;
        canvas.curveTo(data[length - 4], data[length - 3], data[length - 2], data[length - 1]);
    }
    
}