Image Mesh Generator
画像をメッシュ化するTOOLです。
とある目的の為に作成しましたw
アウトライン作成 ->メッシュ作成の為のアウトラインを作成します。
・頂点作成;画像上クリック。
・アウトライン作成の終了(アウトラインを閉じる):始点を再度クリック。
・頂点を追加:アウトライン上をクリック
・頂点を削除:SHIFTキーを押しながら、頂点をクリック
・頂点の移動:閉じたアウトラインの頂点をドラッグ
・線を交差させると、正しくMeshが作成できません
メッシュ化 -> アウトラインをメッシュ化します。
・アウトラインの周りの矩形上の8つの点をクリックする事で、
メッシュ化の為の基準点を変更できます。(メッシュ化の前に選択)
・基準点によって、メッシュの区切り方が変化します。
・キーボードダウン(何でも可)でメッシュが確認できます。
・メッシュ化した画像はドラッグで動かせます。(頂点移動も可)
メッシュ解除 -> 作成したメッシュをアウトラインに戻します。
書き出し -> 頂点情報をXMLに書き出します。
画像の変更 -> 画像が変更できます。HTTP経由での指定もできますが、crossdomainエラーが出るので、アップロードでw
需要があれば直します。
@author narutohyper
/**
* Copyright narutohyper ( http://wonderfl.net/user/narutohyper )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/voB0
*/
package
{
/**
* 画像をメッシュ化するTOOLです。
* とある目的の為に作成しましたw
*
* アウトライン作成 ->メッシュ作成の為のアウトラインを作成します。
* ・頂点作成;画像上クリック。
* ・アウトライン作成の終了(アウトラインを閉じる):始点を再度クリック。
* ・頂点を追加:アウトライン上をクリック
* ・頂点を削除:SHIFTキーを押しながら、頂点をクリック
* ・頂点の移動:閉じたアウトラインの頂点をドラッグ
*
* ・線を交差させると、正しくMeshが作成できません
*
*
* メッシュ化 -> アウトラインをメッシュ化します。
* ・アウトラインの周りの矩形上の8つの点をクリックする事で、
* メッシュ化の為の基準点を変更できます。(メッシュ化の前に選択)
* ・基準点によって、メッシュの区切り方が変化します。
* ・キーボードダウン(何でも可)でメッシュが確認できます。
* ・メッシュ化した画像はドラッグで動かせます。(頂点移動も可)
*
* メッシュ解除 -> 作成したメッシュをアウトラインに戻します。
*
*
* 書き出し -> 頂点情報をXMLに書き出します。
*
* 画像の変更 -> 画像が変更できます。HTTP経由での指定もできますが、crossdomainエラーが出るので、アップロードでw
* 需要があれば直します。
* @author narutohyper
*/
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.geom.Point;
import flash.display.BitmapData;
import flash.display.LineScaleMode;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.system.ApplicationDomain;
import flash.system.System;
import flash.system.Security;
public class Main extends Sprite {
private var _canvas:Sprite
private var _imgArea:Bitmap
private var _buttonSet:Sprite;
private var _urlPanel:ImageLoadPanel;
private var _alert:AlertPanel;
private var _outputPanel:OutputPanel
private var _imgChangeButton:myButton;
private var _makeButton:myButton;
private var _addButton:myButton;
private var _meshMakeButton:myButton;
private var _meshClearButton:myButton;
private var _clearButton:myButton;
private var _outputButton:myButton;
private var _meshs:Array;
private var _bmd:BitmapData;
private var imgLoader:Loader;
public function Main() {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
//Sample画像の読み込み
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
_canvas = new Sprite();
addChild(_canvas)
_bmd = new BitmapData(100,100, true, 0x00000000);
_imgArea=new Bitmap(_bmd)
_canvas.addChild(_imgArea)
_buttonSet = new Sprite();
_buttonSet.visible = false;
addChild(_buttonSet);
_imgChangeButton = new myButton('画像の変更',0,0)
_imgChangeButton.addEventListener(myButton.CLICK, imgChange);
_buttonSet.addChild(_imgChangeButton);
_makeButton = new myButton('アウトラインの作成',100,0)
_makeButton.addEventListener(myButton.CLICK, add);
_buttonSet.addChild(_makeButton);
_addButton = new myButton('アウトラインの追加',100,0)
_addButton.addEventListener(myButton.CLICK, add);
_buttonSet.addChild(_addButton);
_addButton.visible = false
_clearButton = new myButton('クリア', 220, 0)
_clearButton.addEventListener(myButton.CLICK, clear);
_buttonSet.addChild(_clearButton);
_clearButton.visible=false
_meshMakeButton = new myButton('メッシュ化', 280, 0)
_meshMakeButton.addEventListener(myButton.CLICK, makeMesh);
_buttonSet.addChild(_meshMakeButton);
_meshMakeButton.visible = false
_meshClearButton = new myButton('メッシュ解除', 280, 0)
_meshClearButton.addEventListener(myButton.CLICK, clearMesh);
_buttonSet.addChild(_meshClearButton);
_meshClearButton.visible=false
_outputButton = new myButton('書き出し', 380, 0);
_outputButton.addEventListener(myButton.CLICK, output);
_buttonSet.addChild(_outputButton);
_outputButton.visible = false
_outputPanel = new OutputPanel();
addChild(_outputPanel);
_urlPanel = new ImageLoadPanel();
addChild(_urlPanel);
_alert = new AlertPanel('エラー')
addChild(_alert);
_meshs = [];
onStageResize();
this.stage.addEventListener(Event.RESIZE, onStageResize);
//---------------------------------
//Sample画像の読み込み
//---------------------------------
imgLoad('http://marubayashi.net/archive/sample/imagemesh/dolphin.jpg');
}
private function add(e:MouseEvent):void {
_meshs[_meshs.length] = new ImgMesh2d()
_meshs[_meshs.length - 1].bitmapData = _bmd;
_meshs[_meshs.length - 1].addEventListener(ImgMesh2d.CLOSED, closed);
_meshs[_meshs.length - 1].x = _imgArea.x;
_imgChangeButton.visible = false;
_makeButton.visible = false;
_addButton.visible = false;
_clearButton.visible = false;
_meshMakeButton.visible = false;
_meshClearButton.visible = false;
_outputButton.visible = false;
_canvas.addChild(_meshs[_meshs.length-1])
}
private function clear(e:MouseEvent):void {
for (var i:int = 0; i < _meshs.length; i++) {
_meshs[i].destroy();
_meshs[i].removeEventListener(ImgMesh2d.CLOSED, closed);
_canvas.removeChild(_meshs[i])
_meshs[i] = null;
}
_meshs = [];
_clearButton.visible = false;
_meshMakeButton.visible = false;
_meshClearButton.visible = false;
_imgChangeButton.visible = true;
}
//-----------------------------------------
//パスが閉じたら呼ばれる
//-----------------------------------------
private function closed(e:Event):void {
_meshs[_meshs.length-1].removeEventListener(ImgMesh2d.CLOSED, closed);
_meshMakeButton.visible = true
_addButton.visible=true
_outputButton.visible = true
_clearButton.visible = true;
}
private function makeMesh(e:MouseEvent):void {
_meshMakeButton.visible = false;
_meshClearButton.visible = true;
for (var i:int = 0; i < _meshs.length; i++) {
_meshs[i].makeMesh();
}
}
private function clearMesh(e:MouseEvent):void {
_meshMakeButton.visible = true;
_meshClearButton.visible = false;
for (var i:int = 0; i < _meshs.length; i++) {
_meshs[i].clearMesh();
}
}
private function set buttonsEnable(value:Boolean):void {
_imgChangeButton.enabled = value;
_makeButton.enabled = value;
_addButton.enabled = value;
_meshMakeButton.enabled = value;
_meshClearButton.enabled = value;
_clearButton.enabled = value;
_outputButton.enabled = value;
}
//------------------------------------------------------
//画像の入れ替え
//------------------------------------------------------
private function imgChange(e:MouseEvent):void {
buttonsEnable=false
_urlPanel.visible = true;
_urlPanel.addEventListener(ImageLoadPanel.LOAD,load)
_urlPanel.addEventListener(ImageLoadPanel.CANCEL,cancel)
_urlPanel.addEventListener(ImageLoadPanel.UPLOAD,upload)
function load():void {
if (_urlPanel.url) {
imgLoad(_urlPanel.url)
} else {
buttonsEnable = true
}
remove()
}
function upload():void {
if (imgLoader) {
imgLoader.unload();
}
imgLoader = new Loader();
imgLoader.loadBytes(_urlPanel.data);
imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded)
remove()
}
function cancel():void {
buttonsEnable = true
remove()
}
function remove():void {
_urlPanel.removeEventListener(ImageLoadPanel.LOAD,load)
_urlPanel.removeEventListener(ImageLoadPanel.CANCEL,cancel)
_urlPanel.removeEventListener(ImageLoadPanel.UPLOAD,upload)
}
}
//------------------------------------------------
//画像の読み込み
//------------------------------------------------
private function imgLoad(url:String):void {
if (imgLoader) {
imgLoader.unload();
}
imgLoader = new Loader();
Security.loadPolicyFile("http://marubayashi.net/crossdomain.xml");
var urlReq:URLRequest=new URLRequest(url);
var context :LoaderContext = new LoaderContext();
context.applicationDomain = ApplicationDomain.currentDomain;
//imgLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS,progressHandler);
imgLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,onImageIoerror);
imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,onImageLoaded)
imgLoader.load(urlReq, context);
}
private function onImageLoaded(e:Event):void {
_bmd = new BitmapData(imgLoader.width,imgLoader.height, true, 0x00000000);
_bmd.draw(imgLoader, null, null, null, null, true);
_imgArea.bitmapData = _bmd;
_buttonSet.visible = true;
_makeButton.visible = true;
onStageResize();
buttonsEnable = true
}
private function onImageIoerror(e:IOErrorEvent):void {
_alert.setText(e.text);
_alert.addEventListener(myWindow.CLOSE, alertClose);
function alertClose(e:Event):void {
_alert.removeEventListener(myWindow.CLOSE, alertClose);
buttonsEnable = true
}
}
//------------------------------------------------
//XMLデータへのPointの書き出し
//------------------------------------------------
private function output(e:MouseEvent):void {
var result:XML=<date>
</date>;
var tempXML:XML
for (var i:int = 0; i < _meshs.length; i++) {
tempXML = _meshs[i].outputVertices();
tempXML.@id = i
result.mesh[i]=tempXML
}
_outputPanel.visible = true;
_outputPanel.setText(result);
buttonsEnable = false;
_outputPanel.addEventListener(myWindow.CLOSE, outputPanelClose);
_outputPanel.addEventListener(OutputPanel.COPY, outputPanelCopy);
function outputPanelCopy(e:Event):void {
System.setClipboard(result);
}
function outputPanelClose(e:Event):void {
_outputPanel.removeEventListener(OutputPanel.COPY, outputPanelCopy);
_outputPanel.removeEventListener(myWindow.CLOSE, outputPanelClose);
buttonsEnable = true
}
}
private function onStageResize(e:Event=null):void {
_buttonSet.x = int((this.stage.stageWidth - _buttonSet.width) / 2);
_buttonSet.y = 10;
_canvas.x = int((this.stage.stageWidth - _imgArea.width) / 2);
_canvas.y = 40;
}
}
}
import flash.display.Sprite;
import flash.display.LineScaleMode;
import flash.display.SimpleButton;
import flash.text.*
import flash.utils.ByteArray;
import flash.events.MouseEvent;
import flash.events.Event;
//-----------------------------------------------------------
//簡易コンポーネント
//-----------------------------------------------------------
//---------------------------------------
//簡単ボタンクラス
//---------------------------------------
class myButton extends SimpleButton {
public static const CLICK:String = 'click2';
public function myButton($str:String,$x:Number=0,$y:Number=0,$w:Number=0,$h:Number=0) {
this.upState = state($str, $w, $h);
this.overState = state($str, $w, $h,0xFFDDDD);
this.downState = state($str, $w, $h, 0xDDDDFF);
this.hitTestState = state($str, $w, $h, 0xDDDDFF);
this.x = $x;
this.y = $y;
this.addEventListener(MouseEvent.CLICK,inClick)
}
private function state($str:String,$w:Number,$h:Number,$color:uint=0xFFFFFF):Sprite {
var result:Sprite = new Sprite();
var label:TextField=new TextField()
label.autoSize=TextFieldAutoSize.LEFT
label.selectable=false;
label.mouseEnabled=false;
var format:TextFormat=new TextFormat();
format.color=0x666666
format.size=12;
format.font='_ゴシック';
label.defaultTextFormat = format;
label.htmlText = $str;
if (!$w) {
$w = label.width + 20;
}
if (!$h) {
$h = label.height + 4;
}
label.x = int(($w - label.width) / 2);
label.y = int(($h - label.height) / 2);
result.addChild(label)
result.graphics.lineStyle(0,0x666666,0.5,true,LineScaleMode.NONE)
result.graphics.beginFill($color,1)
result.graphics.drawRect(0,0,$w,$h)
return result;
}
private function inClick(e:MouseEvent):void {
if (enabled) {
dispatchEvent(new MouseEvent(CLICK));
}
}
override public function set enabled(value:Boolean):void {
super.enabled = value;
if (value) {
this.alpha = 1
} else {
this.alpha = 0.2
}
}
}
//---------------------------------------
//簡単インプットクラス
//---------------------------------------
class myInput extends Sprite {
private var _label:TextField;
public function myInput($str:String='', $x:Number=0, $y:Number=0, $w:Number = 100, $h:Number = 18) {
this.x = $x;
this.y = $y;
graphics.lineStyle(0,0x666666,0.5,true,LineScaleMode.NONE)
graphics.beginFill(0xFFFFFF,1)
graphics.drawRect(0,0,$w,$h)
_label = new TextField();
_label.autoSize =TextFieldAutoSize.LEFT
_label.selectable=true;
_label.mouseEnabled = true;
_label.mouseWheelEnabled = false;
_label.border = false;
_label.type = TextFieldType.INPUT;
_label.width = $w-4;
_label.height = $h - 2;
_label.x=2
_label.y=1
var format:TextFormat=new TextFormat();
format.color=0x666666
format.size=12;
format.font='_ゴシック';
_label.defaultTextFormat = format
_label.text = $str;
addChild(_label);
}
public function get text():String {
return _label.text;
}
}
//---------------------------------------
//簡単ウインドクラス
//---------------------------------------
class myWindow extends Sprite {
public static const CLOSE:String = 'close';
public function myWindow($str:String = '', $x:Number = 0, $y:Number = 0, $w:Number = 100, $h:Number = 100) {
//---------------------------------------------
//title
//---------------------------------------------
var _label:TextField = new TextField();
_label.autoSize =TextFieldAutoSize.LEFT
_label.selectable=false;
_label.mouseEnabled = false;
_label.x=4
_label.y=3
var format:TextFormat=new TextFormat();
format.color = 0xFFFFFF
format.size=12;
format.font='_ゴシック';
_label.defaultTextFormat = format
_label.text = $str;
addChild(_label);
this.x = $x;
this.y = $y;
resize($w, $h);
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
onStageResize();
stage.addEventListener(Event.RESIZE, onStageResize);
}
public function onStageResize(e:Event=null):void {
x = int((this.stage.stageWidth - width) / 2);
y = int((this.stage.stageHeight - height) / 2);
}
public function resize($w:Number, $h:Number):void {
graphics.clear()
graphics.lineStyle(0, 0x666666, 1, true, LineScaleMode.NONE);
graphics.beginFill(0xFFFFFF, 1);
graphics.drawRect(0, 0, $w, $h);
graphics.beginFill(0xCCCCCC, 1);
graphics.drawRect(0, 0, $w, 20);
}
public function close(e:MouseEvent):void {
visible = false;
dispatchEvent(new Event(CLOSE));
}
}
import flash.net.FileReference;
import flash.net.FileReferenceList;
import flash.utils.ByteArray;
//------------------------------------------------------
//アラートパネル
//------------------------------------------------------
class AlertPanel extends myWindow {
private var _label:TextField;
private var _closeBt:myButton;
public function AlertPanel($str:String = 'エラーが発生しました') {
super('エラー!', 0, 0, 300, 100);
_label = new TextField();
_label.autoSize =TextFieldAutoSize.LEFT
_label.selectable=false;
_label.mouseEnabled = false;
_label.multiline = true;
_label.wordWrap = true;
_label.x=20
_label.y = 40
_label.width = 260;
var format:TextFormat=new TextFormat();
format.color = 0x666666
format.size=12;
format.font='_ゴシック';
_label.defaultTextFormat = format
_label.text = $str;
addChild(_label);
visible = false;
_closeBt = new myButton('閉じる',0, 70);
_closeBt.x = (300 - _closeBt.width)/2;
_closeBt.addEventListener(MouseEvent.CLICK, close);
addChild(_closeBt);
}
public function setText($str:String):void {
_label.text = $str;
visible = true;
_closeBt.y = _label.y + _label.height + 20;
resize(300,_label.y + _label.height + _closeBt.height+30);
onStageResize();
}
}
class OutputPanel extends myWindow {
public static const COPY:String = 'copy';
private var _label:TextField;
private var _closeBt:myButton;
private var _copyBt:myButton;
public function OutputPanel() {
super('XMLへの書き出し', 0, 0, 400, 400);
_label = new TextField();
_label.autoSize =TextFieldAutoSize.NONE
_label.selectable=true;
_label.mouseEnabled = true;
_label.multiline = true;
_label.wordWrap = true;
_label.x=20
_label.y = 30
_label.width = 360;
_label.height = 360;
_label.border = true;
var format:TextFormat=new TextFormat();
format.color = 0x666666
format.size=12;
format.font='_ゴシック';
_label.defaultTextFormat = format
_label.text = '';
addChild(_label);
visible = false;
_closeBt = new myButton('閉じる',0, 70);
_closeBt.x = (400 - _closeBt.width - 20);
_closeBt.addEventListener(MouseEvent.CLICK, close);
addChild(_closeBt);
_copyBt = new myButton('クリップボードにコピー',0, 70);
_copyBt.x = 20;
_copyBt.addEventListener(MouseEvent.CLICK, copy);
addChild(_copyBt);
}
public function copy(e:MouseEvent):void {
dispatchEvent(new Event(COPY));
}
public function setText($str:String):void {
_label.text = $str;
visible = true;
_closeBt.y = _label.y + _label.height + 20;
_copyBt.y = _label.y + _label.height + 20;
resize(400, _label.y + _label.height + _closeBt.height + 30);
onStageResize();
}
}
//------------------------------------------------------
//画像loadパネル
//------------------------------------------------------
class ImageLoadPanel extends myWindow {
public static const CANCEL:String = 'cancel';
public static const LOAD:String = 'load';
public static const UPLOAD:String = 'upload';
private var _file:FileReference;
private var _urlInput:myInput
private const _firstMessage:String='画像をHTTP経由で読み込む場合はURLを入力し、読み込むボタンを押してください'
public function ImageLoadPanel() {
super('新規画像の読み込み',0,0,440,100);
_urlInput = new myInput(_firstMessage,20,36,400);
addChild(_urlInput);
var _changeBt:myButton = new myButton('読み込む', 300, 70);
_changeBt.x = (400 - _changeBt.width + 20);
_changeBt.addEventListener(MouseEvent.CLICK, load);
addChild(_changeBt);
var _uploadBt:myButton = new myButton('画像のアップロード', 300, 70);
_uploadBt.x = int((440 - _uploadBt.width) / 2);
_uploadBt.addEventListener(MouseEvent.CLICK,upload)
addChild(_uploadBt);
var _cancelBt:myButton = new myButton('キャンセル', 20, 70);
_cancelBt.addEventListener(MouseEvent.CLICK,cancel)
addChild(_cancelBt);
visible = false;
}
private function cancel(e:MouseEvent):void {
visible = false;
dispatchEvent(new Event(CANCEL));
}
private function load(e:MouseEvent):void {
visible = false;
dispatchEvent(new Event(LOAD));
}
//------------------------------------------
//ファイルのアップロード
//------------------------------------------
private function upload(e:MouseEvent):void {
visible = false;
_file = new FileReference();
_file.addEventListener(Event.SELECT, loadFileSelected)
_file.addEventListener(Event.CANCEL, loadFileCancel)
_file.browse();
}
private function loadFileSelected(e:Event):void {
_file.removeEventListener(Event.SELECT, loadFileSelected)
_file.removeEventListener(Event.CANCEL, loadFileCancel)
_file.addEventListener(Event.COMPLETE,fileLoaded)
_file.load();
}
private function loadFileCancel(e:Event):void {
_file.removeEventListener(Event.SELECT, loadFileSelected)
_file.removeEventListener(Event.CANCEL, loadFileCancel)
dispatchEvent(new Event(CANCEL));
}
private function fileLoaded(e:Event):void {
_file.removeEventListener(Event.COMPLETE,fileLoaded)
dispatchEvent(new Event(UPLOAD));
}
public function get data():ByteArray {
return _file.data;
}
public function get url():String {
var result:String;
if (_firstMessage != _urlInput.text) {
result=_urlInput.text
}
return result;
}
}
//====================================================================================================================
//画像をメッシュ化するClass
//====================================================================================================================
import flash.display.BitmapData;
import flash.display.LineScaleMode;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
class ImgMesh2d extends Sprite {
public static const CLOSED:String = "closed";
public static const TOP_LEFT:uint = 0;
public static const TOP_CENTER:uint = 1;
public static const TOP_RIGHT:uint = 2;
public static const MIDDLE_LEFT:uint = 3;
public static const MIDDLE_CENTER:uint = 4;
public static const MIDDLE_RIGHT:uint = 5;
public static const BOTTOM_LEFT:uint = 6;
public static const BOTTOM_CENTER:uint = 7;
public static const BOTTOM_RIGHT:uint = 8;
private var _polygons:Vector.<Polygon2d>;
private var _vertices:Vector.<Vertex2d>;
private var _lines:Vector.<Line2d>;
private var _imageLayer:Sprite
private var _vertexLayer:Sprite
private var _lineLayer:Sprite
private var _polygonLayer:Sprite
private var _frameLayer:Sprite
private var _closed:Boolean = false;
private var _meshed:Boolean = false;
private var _bitmapData:BitmapData;
private var _uvtData:Vector.<Number>
private var _verticesData:Vector.<Number>;
private var _lineLock:Boolean = false;
private var _lineOverId:int = -1;
private var _dragPoint:Point;
//自動Mesh生成での基準点
private var _meshBaseMarker:Sprite;
private var _meshBasePoint:uint = TOP_CENTER;
private var _clickArea:Array
public function ImgMesh2d() {
//クリックしたところにPointを置いていく
_imageLayer = new Sprite();
_vertexLayer = new Sprite();
_lineLayer = new Sprite();
_polygonLayer = new Sprite();
_frameLayer = new Sprite();
this.addChild(_imageLayer);
this.addChild(_polygonLayer);
this.addChild(_lineLayer);
this.addChild(_vertexLayer);
this.addChild(_frameLayer);
_polygonLayer.visible = false;
_vertices = new Vector.<Vertex2d>();
_lines = new Vector.<Line2d>();
_polygons = new Vector.<Polygon2d>();
this.addEventListener(Event.ADDED_TO_STAGE, onAdded);
makeBaseFrame();
}
//===========================================================================================
//MouseEvent
//===========================================================================================
private function onAdded(e:Event):void {
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown)
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove)
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown)
stage.addEventListener(KeyboardEvent.KEY_UP,onKeyUp)
}
private function onKeyDown(e:KeyboardEvent):void {
_polygonLayer.visible = true;
}
private function onKeyUp(e:KeyboardEvent):void {
_polygonLayer.visible = false;
}
private function onMouseMove(e:MouseEvent):void {
if (_meshed) {
x=stage.mouseX-parent.x-_dragPoint.x
y=stage.mouseY-parent.y-_dragPoint.y
} else if (_closed) {
} else {
drawLine(mouseX, mouseY)
}
}
private function onMouseUp(e:MouseEvent):void {
if (_meshed) {
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
_imageLayer.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
}
private function onMouseDown(e:MouseEvent):void {
var no:uint;
var i:uint;
if (_meshed) {
_imageLayer.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
_dragPoint = new Point(mouseX, mouseY);
} else if (_closed) {
//line上の場合は、Pointの追加
if (_lineOverId>=0) {
_vertices.splice(_lineOverId + 1, 0, new Vertex2d(_lineOverId + 1, mouseX, mouseY));
_vertexLayer.addChild(_vertices[_lineOverId + 1])
//追加した、以降のIDふりなおし、
no = _lines.length;
_lines[no] = new Line2d();
_lineLayer.addChild(_lines[no]);
for (i = 0; i < _vertices.length; i++) {
_vertices[i].id = i;
if (i == _vertices.length - 1) {
_lines[i].setVertices(i, _vertices[i], _vertices[0]);
} else {
_lines[i].setVertices(i, _vertices[i], _vertices[i + 1]);
}
}
} else if (e.shiftKey) {
//シフトキーが押されていたら削除
if (e.target.hasOwnProperty('id')) {
no = e.target.id;
_vertices[no].destroy();
_vertexLayer.removeChild(_vertices[no]);
_vertices[no] = null;
_vertices.splice(no, 1);
//追加した、以降のIDふりなおし、
no = _lines.length - 1;
_lines[no].destroy();
_lineLayer.removeChild(_lines[no]);
_lines[no] = null;
_lines.splice(no, 1);
for (i = 0; i < _vertices.length; i++) {
_vertices[i].id = i;
if (i == _vertices.length - 1) {
_lines[i].setVertices(i, _vertices[i], _vertices[0]);
} else {
_lines[i].setVertices(i, _vertices[i], _vertices[i + 1]);
}
}
}
}
} else {
if (_vertices.length && _vertices[0].overFlag) {
//閉じる
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove)
no = _lines.length;
_lines[no] = new Line2d();
_lines[no].setVertices(no, _vertices[no], _vertices[0]);
_lineLayer.addChild(_lines[no]);
graphics.clear();
_closed = true;
setBaseFrame()
dispatchEvent(new Event(CLOSED));
} else {
no = _vertices.length;
_vertices[no] = new Vertex2d(no, mouseX, mouseY);
_vertexLayer.addChild(_vertices[no]);
if (_vertices.length > 1) {
no = _lines.length;
_lines[no] = new Line2d();
_lines[no].setVertices(no, _vertices[no], _vertices[no + 1]);
_lineLayer.addChild(_lines[no]);
}
}
}
}
//===========================================================================================
//public
//===========================================================================================
//-----------------------------------------------
//書き出し
//-----------------------------------------------
public function outputVertices():XML {
var result:XML=<mesh>
</mesh>
result.@meshBasePoint=_meshBasePoint
var tempXML:XML
for (var i:uint = 0; i < _vertices.length; i++) {
tempXML=<vertex>
</vertex>
tempXML.@id=_vertices[i].id
tempXML.@x=_vertices[i].x
tempXML.@y=_vertices[i].y
result.data[i]=tempXML
}
return result;
}
//-----------------------------------------------
//削除
//-----------------------------------------------
public function destroy():void {
_imageLayer.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.removeEventListener(KeyboardEvent.KEY_UP,onKeyUp)
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
stage.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown)
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove)
var i:uint
for (i = 0; i < _polygons.length; i++) {
_polygons[i].destroy()
_polygonLayer.removeChild(_polygons[i]);
_polygons[i] = null;
}
_polygons = null;
for (i = 0; i < _lines.length; i++) {
_lines[i].destroy()
_lineLayer.removeChild(_lines[i]);
_lines[i] = null;
}
_lines = null;
for (i = 0; i < _vertices.length; i++) {
_vertices[i].destroy()
_vertexLayer.removeChild(_vertices[i]);
_vertices[i] = null;
}
_vertices=null;
for (i = 0; i < 9; i++) {
_frameLayer.removeChild(_clickArea[i]);
_clickArea[i].removeEventListener(MouseEvent.CLICK,baseChange)
_clickArea[i] = null;
}
_clickArea = null;
_imageLayer.graphics.clear();
_frameLayer.graphics.clear();
}
//-----------------------------------------------
//Mesh削除
//-----------------------------------------------
public function clearMesh():void {
var i:uint
for (i = 0; i < _polygons.length; i++) {
_polygons[i].destroy()
_polygonLayer.removeChild(_polygons[i]);
_polygons[i] = null;
}
_polygons = new Vector.<Polygon2d>();
_imageLayer.graphics.clear();
_meshed = false;
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_imageLayer.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_frameLayer.visible = true;
}
//-----------------------------------------------
//Mesh作成
//-----------------------------------------------
public function makeMesh():void {
//頂点情報のclone
var tempVerties:Vector.<Vertex2d> = _vertices.slice(0);
var maxLength:Number = 0;
var tempLength:Number = 0;
var maxVertex:Vertex2d;
var maxId:int = -1;
var sA:Vertex2d;
var sB:Vertex2d;
var sC:Vertex2d;
var sP:Vertex2d;
var oldCross:int=-2;
var newCross:int=-2;
//基準点
var basePoint:Point
basePoint=new Point(_meshBaseMarker.x,_meshBaseMarker.y);
while (tempVerties.length > 2) {
maxLength = 0;
tempLength = 0;
maxVertex=null;
maxId = -1;
sA=null;
sB=null;
sC=null;
sP=null;
oldCross=-2;
newCross=0;
var i:int
for (i = 0; i < tempVerties.length; i++) {
//中心点,0から各頂点への長さを求める
tempLength = Point.distance(basePoint, tempVerties[i].point);
if (maxLength < tempLength) {
maxLength = tempLength;
maxVertex = _vertices[i]
maxId = i;
}
}
var counter:uint=0
while (counter<tempVerties.length) {
if (maxId>-1) {
if (maxId == 0) {
//三角形用の頂点
sA = tempVerties[tempVerties.length - 1]
sB = tempVerties[maxId];
sC = tempVerties[maxId + 1]
} else if (maxId == tempVerties.length - 1) {
sA = tempVerties[maxId - 1];
sB = tempVerties[maxId];
sC = tempVerties[0];
} else {
sA = tempVerties[maxId - 1];
sB = tempVerties[maxId];
sC = tempVerties[maxId + 1];
}
//内包する頂点が無いかのチェック
var inDelta:Boolean=false;
for (i = 0; i < tempVerties.length; i++) {
if (tempVerties[i] != sA && tempVerties[i] != sB && tempVerties[i] != sC) {
if (InDeltaCheck(sA.point, sB.point, sC.point, tempVerties[i].point)) {
inDelta = true;
break
}
}
}
newCross = crossCheck(sB.point.subtract(sA.point), sB.point.subtract(sC.point));
if (!inDelta && (oldCross==-2 || oldCross==newCross)) {
//内包する点は無い
//三角を形成して、頂点を削除
_polygons[_polygons.length] = new Polygon2d(sA, sB, sC);
_polygonLayer.addChild(_polygons[_polygons.length-1])
tempVerties.splice(maxId, 1);
break;
} else {
//sBからsAへのベクトルとsBからsCへのベクトルの外積を取って保管
if (oldCross==-2) {
oldCross = crossCheck(sB.point.subtract(sA.point), sB.point.subtract(sC.point))
}
if (maxId==0) {
maxId=tempVerties.length-1
} else {
maxId--;
}
counter++;
}
}
}
}
//------------------------------------
//uvtDataの作成
//------------------------------------
if (_bitmapData) {
_uvtData = new Vector.<Number>();
for (i = 0; i < _vertices.length; i++) {
_uvtData[_uvtData.length] = _vertices[i].x / _bitmapData.width
_uvtData[_uvtData.length] = _vertices[i].y / _bitmapData.height
}
}
_meshed = true;
draw();
stage.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_imageLayer.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_frameLayer.visible=false
}
//-----------------------------------------------
//vertexが動いた時にvertexから呼ばれる命令
//-----------------------------------------------
public function vertexMove($id:uint):void {
if ($id == 0) {
_lines[_lines.length-1].draw()
_lines[$id].draw()
} else {
_lines[$id-1].draw()
_lines[$id].draw()
}
draw();
}
//===========================================================================================
//private
//===========================================================================================
private function drawLine($x:Number, $y:Number):void {
if (_vertices.length) {
graphics.clear();
graphics.lineStyle(0, 0xCC0000);
graphics.moveTo(_vertices[_vertices.length - 1].x, _vertices[_vertices.length - 1].y)
graphics.lineTo($x, $y)
}
}
private function crossCheck($p1:Point, $p2:Point):int {
var result:int = 0;
var cross:Number=(($p1.x * $p2.y) - ($p1.y * $p2.x))
if (cross < 0) {
result = -1;
} else if (cross > 0) {
result = 1;
}
return result;
}
private function distance($p1:Point,$p2:Point,$p3:Point):Number {
var vX:Number=$p1.x -$p2.x;
var vY:Number=$p1.y -$p2.y;
return (vY*$p3.x-vX*$p3.y+vX*$p1.y-vY*$p1.x)/Math.sqrt(Math.pow(vX,2)+Math.pow(vY,2));
}
private function isSide($p1:Point,$p2:Point,$p3:Point,$p4:Point):Boolean {
return ((distance($p1,$p2,$p3)*distance($p1,$p2,$p4)) >= 0);
}
private function InDeltaCheck($p1:Point,$p2:Point,$p3:Point,$p4:Point):Boolean {
return isSide($p1,$p2,$p3,$p4) && isSide($p2,$p3,$p1,$p4) && isSide($p3,$p1,$p2,$p4)
}
//---------------------------------------------------
//関連付けられたBitmapDataをdrawTrianglesで描写する。
//---------------------------------------------------
private function draw():void {
if (_meshed) {
_verticesData = new Vector.<Number>();
var i:uint;
for (i = 0; i < _vertices.length; i++) {
_verticesData[_verticesData.length] = _vertices[i].x
_verticesData[_verticesData.length] = _vertices[i].y
}
var _indicesData:Vector.<int> = new Vector.<int>();
for (i = 0; i < _polygons.length; i++) {
_indicesData[_indicesData.length] = _polygons[i].p1.id;
_indicesData[_indicesData.length] = _polygons[i].p2.id;
_indicesData[_indicesData.length] = _polygons[i].p3.id;
}
_imageLayer.graphics.clear();
_imageLayer.graphics.beginBitmapFill(_bitmapData,null,false,true);
_imageLayer.graphics.drawTriangles(_verticesData, _indicesData, _uvtData);
_imageLayer.graphics.endFill()
}
}
//---------------------------------------------------
//メッシュ化基準点UI
//9つの基準点を選択できるようにする
//---------------------------------------------------
private function makeBaseFrame():void {
_clickArea = [];
for (var i:int=0;i<9;i++) {
_clickArea[i] = new Sprite();
_clickArea[i].graphics.beginFill(0x0,0.1)
_clickArea[i].graphics.drawCircle(0,0,4)
_frameLayer.addChild(_clickArea[i]);
_clickArea[i].addEventListener(MouseEvent.CLICK,baseChange)
}
_meshBaseMarker = new Sprite();
_meshBaseMarker.graphics.beginFill(0xFF8800, 1);
_meshBaseMarker.graphics.drawCircle(0, 0, 4);
_frameLayer.addChild(_meshBaseMarker);
_frameLayer.visible=false
}
private function setBaseFrame():void {
var basePoint:Point
var rect:Rectangle = _vertexLayer.getBounds(this)
rect.x -= 10
rect.y -= 10
rect.width += 20
rect.height += 20
_frameLayer.graphics.clear();
_frameLayer.graphics.lineStyle(0,0x000000,0.1,true,LineScaleMode.NONE)
_frameLayer.graphics.drawRect(rect.x,rect.y,rect.width,rect.height)
for (var i:int=0;i<9;i++) {
switch (i) {
case 0:
basePoint=new Point(rect.x,rect.y);
break;
case 1:
basePoint=new Point(rect.x+rect.width/2,rect.y);
break;
case 2:
basePoint=new Point(rect.x+rect.width,rect.y);
break;
case 3:
basePoint=new Point(rect.x,rect.y+rect.height/2);
break;
case 4:
basePoint=new Point(rect.x+rect.width/2,rect.y+rect.height/2);
break;
case 5:
basePoint=new Point(rect.x+rect.width,rect.y+rect.height/2);
break;
case 6:
basePoint=new Point(rect.x,rect.y+rect.height);
break;
case 7:
basePoint=new Point(rect.x+rect.width/2,rect.y+rect.height);
break;
case 8:
basePoint=new Point(rect.x+rect.width,rect.y+rect.height);
break;
}
_clickArea[i].x=basePoint.x
_clickArea[i].y=basePoint.y
}
_frameLayer.visible = true
setBasePoint()
}
private function baseChange(e:MouseEvent):void {
for (var i:int=0;i<9;i++) {
if (e.target == _clickArea[i]) {
_meshBasePoint=i
break;
}
}
setBasePoint()
}
private function setBasePoint():void {
_meshBaseMarker.x=_clickArea[_meshBasePoint].x
_meshBaseMarker.y=_clickArea[_meshBasePoint].y;
}
//===========================================================================================
//Setter&Getter
//===========================================================================================
public function get bitmapData():BitmapData {
return _bitmapData;
}
public function set bitmapData(value:BitmapData):void {
_bitmapData = value;
}
public function get lineLock():Boolean { return _lineLock; }
public function set lineLock(value:Boolean):void
{
_lineLock = value;
}
public function get lineOverId():int { return _lineOverId; }
public function set lineOverId(value:int):void
{
_lineOverId = value;
}
}
//====================================================================================================================
//2D用の頂点Class
//====================================================================================================================
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.geom.Point;
class Vertex2d extends Sprite {
public static const MOVE:String = "move";
public var overFlag:Boolean = false
private var _id:uint;
private var _defColor:uint;
private var _pmc:ImgMesh2d;
private var _size:Number;
public function Vertex2d($id:uint, $x:Number, $y:Number,$size:Number=4, $color:uint=0x000066) {
id = $id;
this.x = $x;
this.y = $y;
_defColor=$color
_size=$size;
draw()
this.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown)
this.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver)
this.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut)
this.addEventListener(Event.ADDED_TO_STAGE,onAdded)
}
private function onAdded(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE,onAdded)
_pmc = this.parent.parent as ImgMesh2d;
}
private function onMouseOver(e:MouseEvent):void {
draw(0xFF0000)
overFlag=true
}
private function onMouseOut(e:MouseEvent):void {
draw()
overFlag=false
}
private function onMouseDown(e:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMove)
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp)
_pmc.lineLock = true;
}
private function onMouseMove(e:MouseEvent):void {
x = _pmc.mouseX
y = _pmc.mouseY
_pmc.vertexMove(id)
dispatchEvent(new Event(MOVE));
}
private function onMouseUp(e:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_MOVE,onMouseMove)
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp)
_pmc.lineLock = false;
}
public function draw($color:uint = 0):void {
if (!$color) {
$color=_defColor
}
graphics.clear();
graphics.beginFill($color)
graphics.drawCircle(0,0,_size);
}
public function destroy():void {
this.removeEventListener(MouseEvent.MOUSE_DOWN,onMouseDown)
this.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver)
this.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOut)
stage.removeEventListener(MouseEvent.MOUSE_MOVE,onMouseMove)
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp)
}
public function get point():Point {
return new Point(x,y)
}
public function get id():uint { return _id; }
public function set id(value:uint):void
{
_id = value;
}
}
//====================================================================================================================
//2D用のラインClass
//====================================================================================================================
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.geom.Point;
class Line2d extends Sprite {
public var overFlag:Boolean = false
private var _id:uint;
private var _v1:Vertex2d;
private var _v2:Vertex2d;
private var _pmc:ImgMesh2d;
private var _defColor:uint=0x009900;
public function Line2d() {
this.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver)
this.addEventListener(MouseEvent.MOUSE_OUT,onMouseOut)
this.addEventListener(Event.ADDED_TO_STAGE,onAdded)
}
public function destroy():void {
this.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver)
this.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOut)
}
private function onAdded(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE,onAdded)
_pmc = this.parent.parent as ImgMesh2d;
}
public function setVertices($id:uint, $v1:Vertex2d, $v2:Vertex2d):void {
_id = $id;
_v1 = $v1;
_v2 = $v2;
draw();
}
public function draw($color:uint = 0):void {
if (!$color) {
$color=_defColor
}
graphics.clear()
graphics.lineStyle(5, 0xFF0000,0);
graphics.moveTo(_v1.x, _v1.y);
graphics.lineTo(_v2.x, _v2.y);
graphics.lineStyle(0, $color);
graphics.moveTo(_v1.x, _v1.y);
graphics.lineTo(_v2.x, _v2.y);
}
private function onMouseOver(e:MouseEvent):void {
if (!_pmc.lineLock) {
draw(0xFF0000)
overFlag = true
_pmc.lineOverId = _id;
}
}
private function onMouseOut(e:MouseEvent):void {
if (!_pmc.lineLock) {
draw()
overFlag = false
_pmc.lineOverId = -1;
}
}
}
//====================================================================================================================
//2D用のポリゴンClass
//====================================================================================================================
import flash.display.Sprite;
import flash.events.Event;
class Polygon2d extends Sprite {
private var _p1:Vertex2d
private var _p2:Vertex2d
private var _p3:Vertex2d
public function Polygon2d($p1:Vertex2d,$p2:Vertex2d,$p3:Vertex2d) {
_p1=$p1
_p2=$p2
_p3=$p3
_p1.addEventListener(Vertex2d.MOVE, draw);
_p2.addEventListener(Vertex2d.MOVE, draw);
_p3.addEventListener(Vertex2d.MOVE, draw);
draw()
}
//-------------------------------------
//テスト用三角の描画
//-------------------------------------
public function draw(e:Event=null):void {
graphics.clear()
graphics.lineStyle(0, 0x000000);
graphics.beginFill(0x00FF00,0.1)
graphics.moveTo(_p1.x, _p1.y);
graphics.lineTo(_p2.x, _p2.y);
graphics.lineTo(_p3.x, _p3.y);
graphics.lineTo(_p1.x, _p1.y);
}
public function destroy():void {
_p1.removeEventListener(Vertex2d.MOVE, draw);
_p2.removeEventListener(Vertex2d.MOVE, draw);
_p3.removeEventListener(Vertex2d.MOVE, draw);
}
public function get p1():Vertex2d { return _p1; }
public function set p1(value:Vertex2d):void
{
_p1 = value;
}
public function get p2():Vertex2d { return _p2; }
public function set p2(value:Vertex2d):void
{
_p2 = value;
}
public function get p3():Vertex2d { return _p3; }
public function set p3(value:Vertex2d):void
{
_p3 = value;
}
}