VectorImageUtil
ベクタ画像の大きさを変更できるようにした。
z:ズームイン
x:ズームアウト
a:視点移動
c:視点リセット
クリック&ドラッグ: 画像選択,画像変形
/**
* Copyright shohei909 ( http://wonderfl.net/user/shohei909 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/rUJh
*/
// forked from shohei909's VectorImage class
package{
//ベクタ画像の大きさを変更できるようにした。
//z:ズームイン
//x:ズームアウト
//a:視点移動
//c:視点リセット
//クリック&ドラッグ: 画像選択,画像変形
import flash.display.*;
import flash.events.*;
import flash.geom.*;
public class VectorTest extends Sprite{
private static const IMG_PASS:Array = [[[1,1.5,0x000000,1.0,0x00FF22,1.0],[12,6,1],[38,6,1],[50,35,1],[40,35,1],[40,50,1],[25,40,1],[10,50,1],[10,35,1],[0,35,1]],[[1,1.5,0x000000,1.0,0xFF0000,1.0],[36,14,0],[14,14,0],[14,22,0],[36,22,0]],[[1,1.5,0x000000,1.0,0xFF0000,1.0],[6,10,0],[22,10,0]],[[1,1.5,0x000000,1.0,0xFF0000,1.0],[42,10,0],[28,10,0]]];
private static const BACK_PASS:Array = [[[1,1.5,0xAAAAAA,1.0,0xFFFF22,0.2],[0,0,0],[0,420,0],[420,420,0],[420,0,0]],[[0,1.5,0xAAAAAA,1.0,0x00FF22,0.0],[190,210,0],[230,210,0]],[[0,1.5,0xAAAAAA,1.0,0x00FF22,0.0],[210,190,0],[210,230,0]]];
private static const FIELD_RECT:Rectangle = new Rectangle(10,10,420,420);
private var field:DynamicSprite;
public function VectorTest():void{
var canvas:Canvas = new Canvas();
var workSpace:WorkSpace = new WorkSpace(canvas);
var segment:Vector.<Array> = VectorImageUtil.segmentation(IMG_PASS)
canvas.addChildren( segment );
field = new DynamicSprite(FIELD_RECT);
field.addChild( new VectorImage(BACK_PASS) );
field.addChild( canvas );
field.addChild( workSpace );
addChild(field);
workSpace.select( canvas.vectorChildren );
stage.addEventListener("keyDown",onKeyDown);
}
public function onKeyDown(e:KeyboardEvent):void{
if(e.keyCode == 88){
field.zoom(field.mouseX,field.mouseY,field.scaleX/2);
}else if(e.keyCode == 90){
field.zoom(field.mouseX,field.mouseY,field.scaleX*2);
}else if(e.keyCode == 65){
field.zoom(field.mouseX,field.mouseY,field.scaleX);
}else if(e.keyCode == 67){
field.reset();
}
}
}
}
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Rectangle;
//拡大、縮小、スライドが滑らかにできるSprite===============================================================
class DynamicSprite extends Sprite{
public var rect:Rectangle;
private var rate:Number = 1;
private var speed:Number = 7;
private var focusX:Number = 0;
private var focusY:Number = 0;
private static const MAX_RATE:Number = 64;
private static const MIN_RATE:Number = 1/16;
public function DynamicSprite(r:Rectangle){
rect = r;
x=rect.x;y=rect.y;
focusX=x;
focusY=y;
addEventListener("enterFrame",focus);
}
//ズーム
public function zoom(fx:Number,fy:Number,r:Number,s:int = 7):void{
if(r>MAX_RATE){r=MAX_RATE;}
if(r<MIN_RATE){r=MIN_RATE;}
speed=s;
rate=r;
focusX=-fx*rate+rect.x+rect.width/2;
focusY=-fy*rate+rect.y+rect.height/2;
}
//ズームのリセット
public function reset():void{
zoom(rect.width/2,rect.width/2,1,3);
}
//焦点の移動
private function focus(e:Event):void{
scaleX = ( scaleX*speed + rate) / (speed+1);
scaleY = ( scaleY*speed + rate) / (speed+1);
x = ( x*speed + focusX) / (speed+1);
y = ( y*speed + focusY) / (speed+1);
}
}
//=====================================================================================================
//ベクタ画像を配置するスプライト===========================================================================================
class Canvas extends Sprite{
public var vectorChildren:Vector.<VectorImage>=new Vector.<VectorImage>();
public function add(pass:Array):void{
var img:VectorImage = new VectorImage(pass);
vectorChildren.push(img);
addChild(img);
}
public function addChildren(pass:Vector.<Array>):void{
var l:int = pass.length;
for(var i:int=0;i<l;i++){
add(pass[i]);
}
}
}
//=====================================================================================================
import flash.events.MouseEvent;
//変形用の枠などを表示する場所============================================================================
class WorkSpace extends Sprite{
private static const MARK_PASS:Array = [[[1,0.5,0xDD0000,1.0,0xFF6666,0.8],[-3,3,0],[-3,-3,0],[3,-3,0],[3,3,0]]];
private static const FRAME_PASS:Array = [[[0,6,0x666666,0.8,0xFF0000,0],[0,0,0],[1,0,0],[1,1,0],[0,1,0],[0,0,0]]];
private static const SELECT_PASS:Array = [[[1,0.5,0x0000FF,0.5,0x0000FF,0.2],[0,0,0],[1,0,0],[1,1,0],[0,1,0]]];
public var targetCanvas:Canvas;
public var selected:Vector.<VectorImage>;
private var marks:Array;
private var frame:VectorImage;
private var selection:VectorImage;
private var moving:Object;
private var selecting:Object;
private var mouseDown:Boolean;
public function WorkSpace(canvas:Canvas):void{
targetCanvas=canvas;
addEventListener(Event.ADDED_TO_STAGE,init);
}
public function init(e:Event=null):void{
removeEventListener(Event.ADDED_TO_STAGE,init);
stage.addEventListener("mouseDown",onMouseDown);
addEventListener("enterFrame",onFrame);
stage.addEventListener("mouseUp",onMouseUp);
moving={move:false,n:0,i:0,j:0,x:0,y:0};
selecting={x:0,y:0};
frame = new VectorImage(FRAME_PASS);
selection = new VectorImage(SELECT_PASS);
marks=[];
addChild(frame);
addChild(selection);
selection.visible=false;
for(var i:int=0;i<3;i++){
marks[i]=[];
for(var j:int=0;j<3;j++){
if(i==1 && j==1){ marks[i][j]=false;}
else{
marks[i][j]=new VectorImage(MARK_PASS);
addChild(marks[i][j]);
}
}
}
reset();
}
public function reset():void{
selected = new Vector.<VectorImage>();
move();
}
public function move():void{
var l:int = selected.length;
if(l>0){
var r:Rectangle = selected[0].getRect(this);
r.width++;r.height++;
for(var n:int=1;n<l;n++){
var r2:Rectangle = selected[n].getRect(this);
r2.width++;r2.height++;
r=r.union(r2);
}
frame.visible = true;
frame.read(VectorImageUtil.transForm( FRAME_PASS,new Matrix(r.width,0,0,r.height,r.x,r.y),new Point(0,0) ));
for(var i:int=0;i<3;i++){
for(var j:int=0;j<3;j++){
if(i!=1 || j!=1){
marks[i][j].visible=true;
marks[i][j].x=r.x+r.width*i/2;
marks[i][j].y=r.y+r.height*j/2;
}
}
}
}else{
frame.visible = false;
for(i=0;i<3;i++){
for(j=0;j<3;j++){
if(i!=1 || j!=1){ marks[i][j].visible=false; }
}
}
}
}
public function select(imgs:Vector.<VectorImage>):void{
selected = imgs;
move();
}
public function onMouseDown(e:MouseEvent):void{
var l:int=selected.length;
mouseDown = true;
if(l>0){
if(frame.hitTestPoint(e.stageX,e.stageY,false)){
moving.move=true;
moving.i=1; moving.j=1;
moving.x=mouseX; moving.y=mouseY;
}
for(var i:int=0;i<3;i++){
for(var j:int=0;j<3;j++){
if( (i!=1 || j!=1) && marks[i][j].hitTestPoint(e.stageX,e.stageY) ){
moving.move=true;
moving.i=i; moving.j=j;
moving.x=mouseX; moving.y=mouseY;
}
}
}
}
if(moving.move!=true){
reset();
selection.visible=true;
selecting.x=mouseX; selecting.y=mouseY;
}
}
public function onFrame(e:Event):void{
if(mouseDown){
if(moving.move){
var moveX:int = mouseX-moving.x; var moveY:int = mouseY-moving.y;
if(Math.abs(moveX)>0 || Math.abs(moveY)>0 ){
var i:int = moving.i; var j:int = moving.j;
moving.x=mouseX; moving.y=mouseY;
if(i!=1||j!=1){
var p1:Point = new Point(marks[0][0].x,marks[0][0].y); var p2:Point = new Point(marks[2][2].x,marks[2][2].y);
var np1:Point = new Point(marks[0][0].x,marks[0][0].y); var np2:Point = new Point(marks[2][2].x,marks[2][2].y);
if(moving.i==0){ np1.x+=moveX; } if(moving.i==2){ np2.x+=moveX; }
if(moving.j==0){ np1.y+=moveY; } if(moving.j==2){ np2.y+=moveY; }
var m:Matrix = new Matrix();
var w:int=p2.x-p1.x;var h:int=p2.y-p1.y;
if(w==0){w=np2.x-np1.x} if(h==0){h=np2.y-np1.y}
if(np2.x-np1.x!=0 && np2.y-np1.y!=0){m.scale( (np2.x-np1.x)/w, (np2.y-np1.y)/h);}
if(np2.x-np1.x<0){moving.i=2-moving.i;} if(np2.y-np1.y<0){moving.j=2-moving.j;}
var p:Point = new Point(marks[2-i][2-j].x,marks[2-i][2-j].y);
var l:int = selected.length;
for(var n:int=0;n<l;n++){
selected[n].read(VectorImageUtil.transForm(selected[n].data,m,p));
}
move();
}else{
l = selected.length;
for(n=0;n<l;n++){ selected[n].read(VectorImageUtil.transForm(selected[n].data, new Matrix(1,0,0,1,moveX,moveY), new Point(0,0))); }
move();
}
}
}else{
var r:Rectangle = new Rectangle(selecting.x,selecting.y);
r.right=mouseX; r.bottom=mouseY;
selection.read(VectorImageUtil.transForm( SELECT_PASS,new Matrix( r.width,0,0,r.height,r.x,r.y),new Point(0,0) ));
}
}
}
public function onMouseUp(e:MouseEvent):void{
if(moving.move==false){
var r:Rectangle = selection.getRect(targetCanvas);
selection.visible=false;
select(VectorImageUtil.select(targetCanvas.vectorChildren,r));
}
mouseDown=false;
moving.move=false;
}
}
//====================================================================================================
import flash.geom.Matrix;
import flash.geom.Point;
//ベクタ画像用のユーティリティ==========================================================================================
class VectorImageUtil{
//画像のdotsをマトリックスで変換したものを返します。
//pointは変換の原点
public static function transForm(pass1:Array,m:Matrix,point:Point):Array{
var pass2:Array = [];
var size:int = pass1.length;
for(var i:int=0;i<size;i++){
pass2[i]=[];pass2[i][0]=[];
for(var n:int=0;n<6;n++){pass2[i][0][n]=pass1[i][0][n];}
var l:int = pass1[i].length;
for(var j:int=1;j<l;j++){
pass2[i][j]=[];
var p:Point = new Point(pass1[i][j][0]-point.x,pass1[i][j][1]-point.y);
p = m.transformPoint(p);
pass2[i][j][0] = p.x+point.x;
pass2[i][j][1] = p.y+point.y;
pass2[i][j][2] = pass1[i][j][2];
}
}
return pass2;
}
//一つのベクタ画像のパスを複数に分解します
public static function segmentation(pass:Array):Vector.<Array>{
var segments:Vector.<Array>=new Vector.<Array>([]);
var size:int = pass.length;
for(var n:int=0;n<size;n++){
segments[n]=[];segments[n][0]=[];
var l:int = pass[n].length;
for(var m:int=0;m<l;m++){
segments[n][0][m]=[];
var l2:int = pass[n][m].length;
for(var k:int = 0;k<l2;k++){segments[n][0][m][k]=pass[n][m][k];}
}
}
return segments;
}
//一つのベクタ画像の頂点が長方形内に含まれるかをテストします。
public static function hitTestRect(pass:Array,rect:Rectangle):Boolean{
var size:int = pass.length;
for(var n:int=0;n<size;n++){
var l:int = pass[n].length;
for(var m:int=1;m<l;m++){
var l2:int = pass[n][m].length;
if(rect.contains(pass[n][m][0],pass[n][m][1])){return true;}
}
}
return false;
}
//長方形内に含まれるベクタ画像を選び出します。
public static function select(imgs:Vector.<VectorImage>,rect:Rectangle):Vector.<VectorImage>{
var selection:Vector.<VectorImage> = new Vector.<VectorImage>();
var size:int = imgs.length;
for(var n:int=0;n<size;n++){
if(hitTestRect(imgs[n].data,rect)){selection.push(imgs[n]);}
}
return selection;
}
//二つの画像の中間の画像を返します。
//time 0:モーフィング開始 1:モーフィング終了
public static function morphing(pass1:Array,pass2:Array,time:Number):Array{
if( morphable(pass1,pass2) ==false){return pass2;}
var neutral:Array = [];
var size:int = pass1.length;
var time2:Number = 1-time;
for(var i:int=0;i<size;i++){
neutral[i]=[];neutral[i][0]=[];
neutral[i][0][0] = pass1[i][0][0];
neutral[i][0][1] = pass1[i][0][1]*time2 + pass2[i][0][1]*time;
neutral[i][0][2] = colorMorphing(pass1[i][0][2],pass2[i][0][2],time);
neutral[i][0][3] = pass1[i][0][3]*time2 + pass2[i][0][3]*time;
neutral[i][0][4] = colorMorphing(pass1[i][0][4],pass2[i][0][4],time);
neutral[i][0][5] = pass1[i][0][5]*time2 + pass2[i][0][5]*time;
var l:int = pass1[i].length;
for(var j:int=1;j<l;j++){
neutral[i][j]=[];
for(var k:int=0;k<3;k++){neutral[i][j][k] = pass1[i][j][k]*time2 + pass2[i][j][k]*time;}
}
}
return neutral;
}
//二つの画像がモーフィング可能かを返します。
public static function morphable(pass1:Array,pass2:Array):Boolean{
var size:int = pass1.length;
if(size != pass2.length){return false;}
for(var i:int=0;i<size;i++){
if(pass1[i][0][0]!=pass2[i][0][0] || pass1[i].length!=pass2[i].length){return false;}
}
return true;
}
//二つの色の中間色を返します。
public static function colorMorphing(color1:uint,color2:uint,time:Number):uint{
return color1;
}
}
//=====================================================================================================
import flash.display.Shape;
//ベクタ画像用クラス=================================================================================================================================================================
class VectorImage extends Shape{
public var data:Array;
public var styles:Vector.<Array>; //styles[][],,,style:[open/close,lineWeight,lineColor,lineAlpha,fillColor,fillAlpha]
public var dots:Vector.<Array>; //dots[][][],,,dot:[x,y,curve]
//コンストラクタ
public function VectorImage(pass:Array){ read(pass); }
//データの読み込み
public function read(pass:Array):void{
data = pass;
styles = new Vector.<Array>();
dots = new Vector.<Array>();
var size:int = pass.length
for(var i:int=0;i<size;i++){
styles[i] = [];dots[i] = [];
for(var j:int=0;j<6;j++){ styles[i][j]=pass[i][0][j]; }
var l:int =pass[i].length-1;
for(var k:int=0;k<l;k++){
dots[i][k] = [];
for(var n:int=0;n<3;n++){ dots[i][k][n]=pass[i][k+1][n]; }
}
}
drow();
}
//データの描画
public function drow():void{
var size:int = styles.length;
graphics.clear();
for(var i:int=0;i<size;i++){
var l:int=dots[i].length;
graphics.lineStyle(styles[i][1],styles[i][2],styles[i][3]);
if(styles[i][0]==1){ graphics.beginFill(styles[i][4],styles[i][5]); var bf:Array=dots[i][l-1];}
else{ bf=dots[i][0];}
graphics.moveTo( center(bf,dots[i][0],0),center(bf,dots[i][0],1) );
for(var j:int=0;j<l-1;j++){ line(bf,dots[i][j],dots[i][j+1]);bf=dots[i][j]; }
if(styles[i][0]==1){ line( bf, dots[i][j], dots[i][0]); }
else{ line(bf, dots[i][j], dots[i][j] ); }
}
}
private function line(dot1:Array,dot2:Array,dot3:Array):void{
graphics.lineTo( center(dot2,dot1,0),center(dot2,dot1,1) );
if(dot2[2]>0){graphics.curveTo( dot2[0],dot2[1],center(dot2,dot3,0),center(dot2,dot3,1) );}
}
private function center(dot1:Array,dot2:Array,xy:int):Number{
if( dot1[2] == 0){return dot1[xy];}
return (dot1[xy]*dot2[2]+dot2[xy]*dot1[2]*dot1[2])/(dot1[2]*dot1[2]+dot2[2]);
}
}
//=========================================================================================================================================================================================