Pure AS3 Free Transform
/**
* Copyright Zebestov ( http://wonderfl.net/user/Zebestov )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/EioN
*/
package {
import flash.system.LoaderContext;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.display.LoaderInfo;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.AntiAliasType;
import flash.text.TextFormatAlign;
import flash.display.StageQuality;
import flash.geom.Matrix;
import flash.display.GradientType;
public class Main extends Sprite {
private var image:BitmapData;
private var canvas:Shape = new Shape();
private var marker0:Sprite, marker1:Sprite, marker2:Sprite, marker3:Sprite;
private var p0:Point, p1:Point, p2:Point, p3:Point;
private var currentDraggable:Sprite;
public function Main() {
stage.quality = StageQuality.BEST;
var mtx:Matrix = new Matrix();
mtx.createGradientBox(stage.stageWidth, stage.stageHeight * 2, -45, 0, 0);
var background:Shape = new Shape();
background.graphics.beginGradientFill(GradientType.LINEAR, [0x666666, 0xa9b5cd], [1.0, 1.0],[0, 255], mtx);
background.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
background.graphics.endFill();
addChild(background);
loadImage();
}
private function start():void {
addChild(canvas);
p0 = new Point();
p1 = new Point();
p2 = new Point();
p3 = new Point();
var sw:int = stage.stageWidth;
var sh:int = stage.stageHeight;
var scale:Number = Math.min((sw - 100) / image.width, (sh - 50) / image.height);
var rect:Rectangle = new Rectangle((sw - image.width * scale) / 2, (sh - image.height * scale) / 2, image.width * scale, image.height * scale);
marker0 = createMarker('1', rect.left, rect.top);
marker1 = createMarker('2', rect.right, rect.top);
marker2 = createMarker('3', rect.right, rect.bottom);
marker3 = createMarker('4', rect.left, rect.bottom);
addChild(marker0);
addChild(marker1);
addChild(marker2);
addChild(marker3);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUpOrLeave);
stage.addEventListener(Event.MOUSE_LEAVE, onMouseUpOrLeave);
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void {
p0.x = marker0.x;
p0.y = marker0.y;
p1.x = marker1.x;
p1.y = marker1.y;
p2.x = marker2.x;
p2.y = marker2.y;
p3.x = marker3.x;
p3.y = marker3.y;
var convexTest1:Boolean = isConvex(p3, p0, p1);
var convexTest2:Boolean = isConvex(p0, p1, p2);
var convexTest3:Boolean = isConvex(p1, p2, p3);
var convexTest4:Boolean = isConvex(p2, p3, p0);
if (convexTest1 == convexTest3 && convexTest2 == convexTest4) {
freeTransform(image, canvas, p0, p1, p2, p3, true);
}
}
private function onMouseDown(event:MouseEvent):void {
var target:Sprite = event.target as Sprite;
if (target.name == 'marker') {
addChild(target);
currentDraggable = target;
target.startDrag(false, stage.getBounds(stage));
}
}
private function onMouseUpOrLeave(event:Event):void {
if (currentDraggable) {
currentDraggable.stopDrag();
currentDraggable = null;
}
}
private function freeTransform(image:BitmapData, canvas:Shape, p1:Point, p2:Point, p3:Point, p4:Point, clear:Boolean = false):void {
var diagonalRatio:Number = Point.distance(p1, p3) / Point.distance(p2, p4);
var a1:Number = p1.y - p3.y;
var b1:Number = p3.x - p1.x;
var c1:Number = p1.x * p3.y - p3.x * p1.y;
var a2:Number = p2.y - p4.y;
var b2:Number = p4.x - p2.x;
var c2:Number = p2.x * p4.y - p4.x * p2.y;
var intersection:Point = new Point((c2*b1-c1*b2)/(a1*b2-a2*b1), (a2*c1-a1*c2)/(a1*b2-a2 * b1));
var t1:Number = 1 / Point.distance(p3, intersection) * diagonalRatio;
var t2:Number = 1 / Point.distance(p4, intersection);
var t3:Number = 1 / Point.distance(p1, intersection) * diagonalRatio;
var t4:Number = 1 / Point.distance(p2, intersection);
var vertices:Vector.<Number> = new Vector.<Number>();
vertices.push(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y);
var indices:Vector.<int> = new Vector.<int>();
indices.push(0, 1, 2, 2, 3, 0);
var uvtdata:Vector.<Number> = new Vector.<Number>();
uvtdata.push(0, 0, t1, 1, 0, t2, 1, 1, t3, 0, 1, t4);
if (clear) {
canvas.graphics.clear();
}
canvas.graphics.beginBitmapFill(image, null, false, true);
canvas.graphics.drawTriangles(vertices, indices, uvtdata);
canvas.graphics.endFill();
}
private function isConvex(p1:Point, p2:Point, p3:Point):Boolean {
var a:Point = new Point(p1.x - p2.x, p1.y - p2.y);
var b:Point = new Point(p3.x - p2.x, p3.y - p2.y);
return ((a.x * b.y - a.y * b.x) <= 0);
}
private function createMarker(label:String, x:int, y:int):Sprite {
var result:Sprite = new Sprite();
result.graphics.lineStyle(1, 0xffffff);
result.graphics.beginFill(0x3399ff);
result.graphics.drawCircle(0, 0, 10);
result.graphics.endFill();
var tfld:TextField = new TextField();
tfld.defaultTextFormat = new TextFormat('Arial', 14, 0xffffff, true, null, null, null, null, TextFormatAlign.CENTER);
tfld.text = label;
tfld.width = 20;
tfld.height = 20;
tfld.x = -10;
tfld.y = -10;
result.addChild(tfld);
result.x = x;
result.y = y;
result.name = 'marker';
result.mouseChildren = false;
return result;
}
private function loadImage():void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
loader.load(new URLRequest('http://assets.wonderfl.net/images/related_images/4/47/4786/478610286ba93f45518f4f2e9d0bf0326035cc1b'), new LoaderContext(true));
}
private function onLoadComplete(event:Event):void {
(event.target as LoaderInfo).removeEventListener(Event.COMPLETE, onLoadComplete);
image = ((event.target as LoaderInfo).content as Bitmap).bitmapData;
start();
}
}
}