VectorImage用ツール いろいろ
ベクタ画像の大きさを変更できるようにした。
z:ズームイン
x:ズームアウト
a:視点移動
c:視点リセット
クリック&ドラッグ: 画像選択,画像変形
delete: 選択画像消去
/**
* Copyright shohei909 ( http://wonderfl.net/user/shohei909 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/kQEf
*/
// forked from shohei909's VectorImageUtil
// forked from shohei909's VectorImage class
//ベクタ画像の大きさを変更できるようにした。
//z:ズームイン
//x:ズームアウト
//a:視点移動
//c:視点リセット
//クリック&ドラッグ: 画像選択,画像変形
//delete: 選択画像消去
package{
import flash.display.*;
import flash.events.*;
import flash.geom.*;
[SWF(backgroundColor="#333333", frameRate="60", width="465", height="465")]
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 FIELD_RECT:Rectangle = new Rectangle(10,10,445,400);
private var field:SlideSprite;
public function VectorTest():void{
var canvas:Canvas = new Canvas(100,100);
var workSpace:WorkSpace = new WorkSpace(canvas);
var segment:Vector.<Array> = VectorImageUtil.segmentation(IMG_PASS)
canvas.addChildren( segment );
field = new SlideSprite(FIELD_RECT);
field.addChild( canvas ); field.addChild( workSpace );
addChild(field);
var frame:Bitmap = new Bitmap(new BitmapData(465,465,true,0xFF000000));
frame.bitmapData.fillRect(FIELD_RECT,0x00000000);
addChild(frame);
stage.addEventListener("keyDown",onKeyDown);
}
public function onKeyDown(e:KeyboardEvent):void{
var c:DynamicSprite = field.container;
if(e.keyCode == 88){ c.zoom(c.mouseX,c.mouseY,c.scaleX/2);
}else if(e.keyCode == 90){ c.zoom(c.mouseX,c.mouseY,c.scaleX*2);
}else if(e.keyCode == 65){ c.zoom(c.mouseX,c.mouseY,c.scaleX);
}else if(e.keyCode == 67){ c.reset(); }
}
}
}
import flash.events.KeyboardEvent;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.BlendMode;
import flash.events.Event;
import flash.geom.Rectangle;
//拡大、縮小、スライドが滑らかにできるSprite===============================================================
class DynamicSprite extends Sprite{
public var rect:Rectangle; public var rate:Number = 1; public var focusX:Number = 0; public var focusY:Number = 0;
protected var speed:Number = 7;
public static const MAX_RATE:Number = 64; public static const MIN_RATE:Number = 1/16;
public static const ON_ZOOM:String = "zoom";
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.height/2,1,3); }
//焦点の移動
protected function focus(e:Event):void{
if( Math.abs(x-focusX)>0.1 || Math.abs(y-focusY)>0.1 || Math.abs(rate-scaleY)>0.00001 || Math.abs(rate-scaleX)>0.00001){
scaleX = ( scaleX*speed + rate) / (speed+1);scaleY = ( scaleY*speed + rate) / (speed+1);
x = ( x*speed + focusX) / (speed+1); y=( y*speed + focusY) / (speed+1);
dispatchEvent(new Event("zoom"));
}
}
}
//=====================================================================================================
class SlideSprite extends Sprite{
private static const BAR_WIDTH:Number = 15;
private static const BAR_COLOR:Number = 0x222222;
private static const BACK_COLOR:Number = 0x111111;
private static const BAR_PASS:Array = [[[1,0.0,0x440000,0.0,0x441111,1.0],[0,0,0],[0,1,0],[1,1,0],[1,0,0]]];
public var container:DynamicSprite;
public var maskSprite:Sprite = new Sprite();
public function SlideSprite(r:Rectangle){
x=r.x; y=r.y;
graphics.beginFill(BAR_COLOR,1.0); graphics.drawRect(0,0,r.width,r.height);
graphics.beginFill(BACK_COLOR,1.0); graphics.drawRect(0,0,r.width-BAR_WIDTH,r.height-BAR_WIDTH);
maskSprite.graphics.beginFill(0x000000,1.0); maskSprite.graphics.drawRect(0,0,r.width-BAR_WIDTH,r.height-BAR_WIDTH);
container = new DynamicSprite( new Rectangle(0,0,r.width-BAR_WIDTH,r.height-BAR_WIDTH) );
container.mask = maskSprite;
super.addChild(container); super.addChild(maskSprite);
container.addEventListener("zoom",setBar);
setBar();
}
override public function addChild(spr:DisplayObject):DisplayObject{
return container.addChild(spr);
}
private function setBar(e:Event=null):void{
var outR:Rectangle = maskSprite.getRect(this);
var inR:Rectangle =outR.union(container.getRect(this));
}
}
//ベクタ画像を配置するスプライト===========================================================================================
class Canvas extends Sprite{
public var vectorChildren:Vector.<VectorImage>=new Vector.<VectorImage>();
private static const BACK_PASS:Array = [[[1,0.5,0xDDDDDD,1.0,0xFFFFFF,1.0],[0,0,0],[0,1,0],[1,1,0],[1,0,0]]];
public function Canvas(w:int,h:int){
addChild( new VectorImage(VectorImageUtil.transform( BACK_PASS, new Matrix(w,0,0,h),new Point)) );
}
private 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]);
}
//ベクタ画像をリストから削除
public function removeChildren(imgs:Vector.<VectorImage>):void{
for each(var img:VectorImage in imgs) {
removeChild(img); vectorChildren.splice(vectorChildren.indexOf(img),1)
}
}
}
//=====================================================================================================
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,3,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 canvas: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;
private var power:Boolean=false;
public function WorkSpace(canvas:Canvas):void{
this.canvas=canvas; addEventListener(Event.ADDED_TO_STAGE,init);
}
public function init(e:Event=null):void{
removeEventListener(Event.ADDED_TO_STAGE,init);
moving={move:false,n:0,i:0,j:0,x:0,y:0}; selecting={x:0,y:0};
marks=[];
frame = new VectorImage(FRAME_PASS); selection = new VectorImage(SELECT_PASS);
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]);
}
}
}
on();
}
//このワークスペースを機能させる
public function on():void{
if(power==false){
visible=true;
stage.addEventListener("mouseDown",onMouseDown);
addEventListener("enterFrame",onFrame);
stage.addEventListener("mouseUp",onMouseUp);
stage.addEventListener("keyDown",onKeyDown);
reset();
}
}
//このワークスペースの機能を停止する
public function off():void{
if(power==false){
visible=false;
stage.removeEventListener("mouseDown",onMouseDown);
removeEventListener("enterFrame",onFrame);
stage.removeEventListener("mouseUp",onMouseUp);
stage.removeEventListener("keyDown",onKeyDown);
}
}
//選択している画像をリセット
private function reset():void{ selected = new Vector.<VectorImage>(); update(); }
//画像を選択
private function select(imgs:Vector.<VectorImage>):void{ selected=imgs; update(); }
//画像を消去
private function del():void{ canvas.removeChildren(selected);reset(); }
//選択している画像を更新
private function update():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 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:Number=mouseX-moving.x; var moveY:Number=mouseY-moving.y;
if(Math.abs(moveX)>0 || Math.abs(moveY)>0 ){
var i:Number=moving.i; var j:Number=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:Number=p2.x-p1.x; var h:Number=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));
}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))); }
}
update();
}
}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(canvas);
selection.visible=false;
select(VectorImageUtil.select(canvas.vectorChildren,r));
}
mouseDown=false; moving.move=false;
}
//キー操作
public function onKeyDown(e:KeyboardEvent):void{
if(e.keyCode==46){del();}
}
}
//====================================================================================================
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]);
}
}
//=========================================================================================================================================================================================