forked from: 画像のアウトラインを一筆書き
// forked from xlune's 画像のアウトラインを一筆書き
package {
import __AS3__.vec.Vector;
import flash.display.BitmapData;
import flash.display.CapsStyle;
import flash.display.Graphics;
import flash.display.JointStyle;
import flash.display.LineScaleMode;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.net.URLRequest;
import flash.system.LoaderContext;
[SWF(width=465, height=465, frameRate=15, backgroundColor=0xFFFFFF)]
public class main extends Sprite
{
//画面幅
private var _width:uint = 465;
//画面高さ
private var _height:uint = 465;
//精度
private var _prec:uint = 1;
//描画スピード
private var _speed:uint = 10;
//閾値
private var _threshold:uint = 0xD0;
//ガイド画像
private var _imgUrl:String = 'http://farm4.static.flickr.com/3616/3403716568_61e499c7f5.jpg';
//開始位置
private var _startPoint:Point = new Point(0, 0);
//終了位置
private var _endPoint:Point = new Point(_width, _height);
private var _img:Loader;
private var _guide:BitmapData;
private var _canvas:Sprite;
private var _gp:Graphics;
private var _pointStatus:Vector.<PointStatus>;
private var _basePoint:Point;
/**
* コンストラクタ
*/
public function main()
{
var request:URLRequest = new URLRequest(_imgUrl);
var context:LoaderContext = new LoaderContext(true);
_img = new Loader();
_img.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
_guide = new BitmapData(_width, _height, false, 0x00FFFFFF);
_canvas = new Sprite();
try {
_img.load(request, context);
} catch (error:Error) {
trace("image load failed.");
}
}
/**
* Event Complete Handler
*/
private function completeHandler(event:Event):void
{
_img.x = _width / 2 - _img.width / 2;
_img.y = _height / 2 - _img.height / 2;
_img.alpha = 0.1;
var gMatrix:Matrix = new Matrix();
gMatrix.tx = _img.x;
gMatrix.ty = _img.y;
_guide.draw(_img, gMatrix);
_pointStatus = new Vector.<PointStatus>();
makePoints();
addChild(_img);
addChild(_canvas);
_gp = _canvas.graphics;
_gp.lineStyle(1, 0xFF0000, 1, true, LineScaleMode.NONE, CapsStyle.ROUND, JointStyle.MITER, 2);
_basePoint = new Point(_startPoint.x, _startPoint.y);
_gp.moveTo(_basePoint.x, _basePoint.y);
this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
/**
* Event EnterFrame Handler
*/
private function enterFrameHandler(event:Event):void
{
if(isAllSelected())
{
_basePoint = new Point(_endPoint.x, _endPoint.y);
_gp.lineTo(_basePoint.x, _basePoint.y);
this.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
else
{
for(var i:uint=0; i<_speed; i++)
{
_basePoint = getNearPoint(_basePoint);
if(_basePoint) _gp.lineTo(_basePoint.x, _basePoint.y);
}
}
}
/**
* 近いポイント取得
*/
private function getNearPoint(base:Point):Point
{
var minNum:Number = 0, selectItem:PointStatus, rePoint:Point;
_pointStatus.forEach(function(item:PointStatus, index:uint, vector:Vector.<PointStatus>):void
{
if(!item.isSelected){
var n:Number = Point.distance(base, new Point(item.x, item.y));
if(!selectItem || n < minNum){
minNum = n;
selectItem = item;
}
}
});
if(selectItem)
{
selectItem.isSelected = true;
rePoint = new Point(selectItem.x, selectItem.y);
return rePoint;
}
return null;
}
/**
* 全通過チェック
*/
private function isAllSelected():Boolean
{
var flg:Boolean = true;
_pointStatus.every(function(item:PointStatus, index:uint, vector:Vector.<PointStatus>):Boolean
{
if(!item.isSelected)
{
flg = false;
return false;
}
return true;
}, this);
return flg;
}
/**
* 境界点生成
*/
private function makePoints():void
{
for(var j:uint=0,jMax:uint=_height; j<jMax; j+=_prec){
for(var i:uint=0,iMax:uint=_width; i<iMax; i+=_prec){
if(isUniquePoint(i, j)){
_pointStatus.push(new PointStatus(i,j));
}
}
}
}
/**
* 境界点を抽出
*/
private function isUniquePoint(posX:uint, posY:uint):Boolean
{
if(isFillPoint(posX, posY))
{
if(!isFillPoint(posX, posY-_prec)
|| !isFillPoint(posX+_prec, posY)
|| !isFillPoint(posX, posY+_prec)
|| !isFillPoint(posX-_prec, posY))
{
return true;
}
}
return false;
}
/**
* 2値化
*/
private function isFillPoint(posX:int, posY:int):Boolean
{
if(posX < 0 || posX > _width) return false;
if(posY < 0 || posY > _height) return false;
var color:uint = _guide.getPixel(posX, posY);
color = (((color >> 16) & 0xff) + ((color >> 8) & 0xff) + (color & 0xff)) / 3;
if(color < _threshold) return true;
return false;
}
}
}
class PointStatus
{
private var _x:uint;
private var _y:uint;
private var _group:uint = 0;
private var _isSelected:Boolean = false;
public function PointStatus(numX:uint, numY:uint, numGroup:uint=0)
{
x = numX;
y = numY;
group = numGroup;
}
public function set x(val:uint):void
{
_x = val;
}
public function get x():uint
{
return _x;
}
public function set y(val:uint):void
{
_y = val;
}
public function get y():uint
{
return _y;
}
public function set group(val:uint):void
{
_group = val;
}
public function get group():uint
{
return _group;
}
public function set isSelected(val:Boolean):void
{
_isSelected = val;
}
public function get isSelected():Boolean
{
return _isSelected;
}
}