forked from: Illustrotor風ペンツール ver.6(未完成)
ver.3:3次ベジェ曲線を再現
ver.4:始点-終点を結ぶと閉じる
ver.5:閉じたあとにアンカーとハンドルが操作可能
今回はさらにアンカーポイントを追加できるようにする
/**
* Copyright taka_milk ( http://wonderfl.net/user/taka_milk )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/aHvD
*/
// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.6(未完成)
// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.5
// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.4
// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.3
// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.2
// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.1
//ver.3:3次ベジェ曲線を再現
//ver.4:始点-終点を結ぶと閉じる
//ver.5:閉じたあとにアンカーとハンドルが操作可能
//今回はさらにアンカーポイントを追加できるようにする
package{
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.MouseEvent;
import flash.text.TextField;
public class PenTool extends Sprite{
private var bezierPointStage:Sprite = new Sprite();
private var bezierCurve:BezierCurveDrawer = new BezierCurveDrawer();
private var txt:TextField = new TextField();
private var targetIndex:uint;
private var targetType:String;
public function PenTool(){
addChild(bezierCurve);
addChild(bezierPointStage);
addChild(txt);
txt.width = 400;
txt.height = 20;
stage.addEventListener(MouseEvent.MOUSE_DOWN, addBezierPoint);
}
private function addBezierPoint(event:MouseEvent):void{
switch(event.type){
case MouseEvent.MOUSE_DOWN:
if(bezierCurve.finalize){
targetIndex = 0;
txt.text = "ベジェ曲線を閉じました。";
stage.removeEventListener(MouseEvent.MOUSE_DOWN, addBezierPoint);
bezierCurve.push(bezierCurve.getIndexAt(0));
bezierCurve.getIndexAt(0).anchor.removeEventListener(MouseEvent.ROLL_OVER, finalizeBezier);
bezierCurve.getIndexAt(0).anchor.removeEventListener(MouseEvent.ROLL_OUT, finalizeBezier);
}
else {
targetIndex = bezierCurve.length;
var bezierPoint:BezierPoint = new BezierPoint(new Point(mouseX, mouseY));
bezierCurve.push(bezierPoint);
if(!targetIndex) {
bezierPoint.anchor.addEventListener(MouseEvent.ROLL_OVER, finalizeBezier);
bezierPoint.anchor.addEventListener(MouseEvent.ROLL_OUT, finalizeBezier);
}
bezierPointStage.addChild(bezierPoint);
}
stage.addEventListener(MouseEvent.MOUSE_MOVE, moveBezierPoint);
stage.addEventListener(MouseEvent.MOUSE_UP,
function defineBezierPoint():void{
if(bezierCurve.finalize) {
bezierCurve.addBezierCurveEvent(MouseEvent.ROLL_OVER, addBezierPoint);
bezierCurve.addBezierCurveEvent(MouseEvent.ROLL_OUT, addBezierPoint);
bezierCurve.addBezierCurveEvent(MouseEvent.CLICK, addBezierPoint);
bezierCurve.addBezierPointEvent(MouseEvent.ROLL_OVER, moveBezierPoint);
bezierCurve.addBezierPointEvent(MouseEvent.ROLL_OUT, moveBezierPoint);
bezierCurve.addBezierPointEvent(MouseEvent.MOUSE_DOWN, moveBezierPoint);
}
txt.text = "";
stage.removeEventListener(MouseEvent.MOUSE_MOVE, moveBezierPoint);
}
);
break;
case MouseEvent.CLICK:
txt.text = "アンカーポイント追加しました。";
break;
case MouseEvent.ROLL_OVER:
txt.text = "アンカーポイント追加します。";
break;
case MouseEvent.ROLL_OUT:
txt.text = "";
break;
}
}
private function moveBezierPoint(event:MouseEvent):void{
var targetPoint:BezierPoint = bezierCurve.getIndexAt(targetIndex);
switch(event.type){
case MouseEvent.MOUSE_MOVE:
var f:Number = -targetPoint.f(targetType);
//if(inFinite(f))) f = -1;
txt.text = String(f);
//if(KeyboardEvent.altKey) txt.text = "alt";
switch(targetType){
case "anchor":
bezierCurve.setIndexAt(new Point(mouseX, mouseY), null, null, targetIndex);
break;
case "handleA":
//bezierCurve.setIndexAt(null, new Point(mouseX, mouseY), null, targetIndex);), targetIndex);
if(isFinite(f)) bezierCurve.setIndexAt(null, new Point(mouseX, mouseY), Point.interpolate(targetPoint.handleAPoint, targetPoint.anchorPoint, f), targetIndex);
break;
case "handleB":
//bezierCurve.setIndexAt(null, null, new Point(mouseX, mouseY), targetIndex);
if(isFinite(f)) bezierCurve.setIndexAt(null, Point.interpolate(targetPoint.handleBPoint, targetPoint.anchorPoint, f), new Point(mouseX, mouseY), targetIndex);
break;
default:
bezierCurve.setIndexAt(null,new Point(mouseX, mouseY),Point.interpolate(targetPoint.handleAPoint, targetPoint.anchorPoint, -1), targetIndex);
break;
}
break;
case MouseEvent.MOUSE_DOWN:
stage.addEventListener(MouseEvent.MOUSE_MOVE, moveBezierPoint);
stage.addEventListener(MouseEvent.MOUSE_UP,
function removeEvent():void{
event.target.removeEventListener(MouseEvent.MOUSE_MOVE, moveBezierPoint);
}
);
break;
case MouseEvent.ROLL_OVER:
txt.text = event.target.type;
targetType = event.target.type;
targetIndex = bezierCurve.indexOf(event.target.parent as BezierPoint);
break;
case MouseEvent.ROLL_OUT:
txt.text = "";
break;
}
event.updateAfterEvent();
}
private function finalizeBezier(event:MouseEvent):void{
if(targetIndex) {
switch(event.type){
case MouseEvent.ROLL_OVER:
txt.text = "ベジェ曲線を閉じます。";
bezierCurve.finalize = true;
break;
case MouseEvent.ROLL_OUT:
txt.text = "";
bezierCurve.finalize = false;
break;
}
}
}
}
}
import flash.geom.Point;
import flash.display.Sprite;
//---------
//3次ベジェ曲線を繋げてグラフィックを描くクラス
class BezierCurveDrawer extends Sprite{
private var _pointArray:Array = new Array(); //BezierPointを格納する変数
private var _curveArray:Array = new Array(); //BezierCurveを格納する変数
public var finalize:Boolean = false; //BezierCurveの開閉を監視
public function BezierCurveDrawer(){
}
public function indexOf(bezierPoint:BezierPoint):int{
return _pointArray.indexOf(bezierPoint);
}
public function indexOfCurve(bezierCurve:BezierCurve):int{
return _curveArray.indexOf(bezierCurve);
}
public function getIndexAt(_index:uint):BezierPoint{
return _pointArray[_index];
}
public function setIndexAt(_anchor:Point, _handleA:Point, _handleB:Point, _index:uint):void{
if(_index < length){
if(_anchor) _pointArray[_index].anchorPoint = _anchor;
if(_handleA) _pointArray[_index].handleAPoint = _handleA;
if(_handleB) _pointArray[_index].handleBPoint = _handleB;
var prev:int = _index > 0 ? _index-1 : finalize ? length-1 : -1;
var next:int = !finalize ? -1 : _index < length ? _index : 0;
if(_curveArray[prev]) {
_curveArray[prev].setPoint(null, null, _pointArray[_index].handleBPoint, _pointArray[_index].anchorPoint);
_curveArray[prev].draw();
}
if(_curveArray[next]){
_curveArray[next].setPoint(_pointArray[_index].anchorPoint, _pointArray[_index].handleAPoint, null, null);
_curveArray[next].draw();
}
}
}
//イベント
public function addBezierPointEvent(type:String, listener:Function):void{
for each(var bezierPoint:BezierPoint in _pointArray){
bezierPoint.anchor.addEventListener(type,listener);
bezierPoint.handleA.addEventListener(type,listener);
bezierPoint.handleB.addEventListener(type,listener);
}
}
public function removeBezierPointEvent(type:String, listener:Function):void{
for each(var bezierPoint:BezierPoint in _pointArray){
bezierPoint.anchor.removeEventListener(type,listener);
bezierPoint.handleA.removeEventListener(type,listener);
bezierPoint.handleB.removeEventListener(type,listener);
}
}
public function addBezierCurveEvent(type:String, listener:Function):void{
for each(var bezierCurve:BezierCurve in _curveArray){
bezierCurve.addEventListener(type,listener);
}
}
public function push(bezierPoint:BezierPoint):void{
if(length) {
var bezierCurve:BezierCurve = new BezierCurve(_pointArray[length-1].anchorPoint, _pointArray[length-1].handleAPoint,
bezierPoint.handleBPoint, bezierPoint.anchorPoint);
addChild(bezierCurve);
_curveArray.push(bezierCurve);
}
if(!finalize) _pointArray.push(bezierPoint);
}
public function get length():uint{
return _pointArray.length;
}
}
//---------
//4点で3次ベジェ曲線の計算・描画クラス
class BezierCurve extends Sprite{
public var a:Point; //anchorA
public var b:Point; //handleA
public var c:Point; //handleB
public var d:Point; //anchorB
public function BezierCurve(a:Point, b:Point, c:Point, d:Point){
this.a = a;
this.b = b;
this.c = c;
this.d = d;
draw();
}
public function setPoint(a:Point, b:Point, c:Point, d:Point):void{
if(a) this.a = a;
if(b) this.b = b;
if(c) this.c = c;
if(d) this.d = d;
}
public function draw():void{
graphics.clear();
graphics.lineStyle(3,0x666666);
graphics.moveTo(a.x, a.y);
for each(var bezierPoint:Point in BezierCurve.bezierValues(a,b,c,d,20)){
graphics.lineTo(bezierPoint.x,bezierPoint.y);
}
}
public static function bezierValue(a:Point, b:Point, c:Point, d:Point,t:Number):Point{
if(t < 0 || t > 1) return null;
var _p4:Point = Point.interpolate(b, a, t);
var _p5:Point = Point.interpolate(c, b, t);
var _p6:Point = Point.interpolate(d, c, t);
var _p7:Point = Point.interpolate(_p5, _p4, t);
var _p8:Point = Point.interpolate(_p6, _p5, t);
return Point.interpolate(_p8, _p7, t);
}
public static function bezierValues(a:Point, b:Point, c:Point, d:Point,_quality:uint = 10):Array{
if(a.equals(d)) return [a];
var valueArray:Array = new Array();
for(var i:uint = 0; i <= _quality; i++){
valueArray.push(bezierValue(a,b,c,d,i/_quality));
}
return valueArray;
}
}
//---------
//アンカー,ハンドルA,ハンドルBを格納したクラス
class BezierPoint extends Sprite{
private var _anchor:PointSprite;
private var _handleA:PointSprite;
private var _handleB:PointSprite;
public function BezierPoint(_anchor:Point){
anchorPoint = _anchor;
}
private function drawLine():void{
graphics.clear();
graphics.lineStyle(1,0x00ffff);
if(_handleA){
graphics.moveTo(anchor.x, anchor.y);
graphics.lineTo(handleA.x, handleA.y);
}
if(_handleB){
graphics.moveTo(anchor.x, anchor.y);
graphics.lineTo(handleB.x, handleB.y);
}
}
public function f(_handle:String):Number{
if(_handle == "handleA") {
//if(anchorPoint.equals(handleAPoint)) return -1;//Point.distance(anchorPoint, handleBPoint);
return Point.distance(anchorPoint, handleBPoint)/Point.distance(anchorPoint, handleAPoint);
}else if(_handle == "handleB") {
//if(anchorPoint.equals(handleBPoint)) return Point.distance(anchorPoint, handleAPoint);
return Point.distance(anchorPoint, handleAPoint)/Point.distance(anchorPoint, handleBPoint);
}else return 0;
}
//プロパティ
//anchor
public function set anchorPoint(_point:Point):void{
if(!_anchor){
_anchor = new PointSprite(_point, "anchor");
addChild(_anchor);
}
else{
var subPoint:Point = _point.subtract(_anchor.point);
_anchor.drawPoint(_point);
if(_handleA) _handleA.drawPoint(_handleA.point.add(subPoint));
if(_handleB) _handleB.drawPoint(_handleB.point.add(subPoint));
drawLine();
}
}
public function get anchorPoint():Point{
return _anchor.point;
}
public function get anchor():Sprite{
return _anchor as Sprite;
}
//handleA
public function set handleAPoint(_point:Point):void{
if(!_handleA) {
_handleA = new PointSprite(_point, "handleA");
addChild(_handleA);
}
else {
_handleA.drawPoint(_point);
}
drawLine();
}
public function get handleAPoint():Point{
if(_handleA) return _handleA.point;
return _anchor.point;
}
public function get handleA():Sprite{
if(_handleA) return _handleA;
return _anchor;
}
//handleB
public function set handleBPoint(_point:Point):void{
if(!_handleB) {
_handleB = new PointSprite(_point, "handleB");
addChild(_handleB)
}
else {
_handleB.drawPoint(_point);
}
drawLine();
}
public function get handleBPoint():Point{
if(_handleB) return _handleB.point;
return _anchor.point;
}
public function get handleB():Sprite{
if(_handleA) return _handleB;
return _anchor;
}
}
//---------
//アンカー,ハンドルの描画用クラス
class PointSprite extends Sprite{
public var point:Point;
public var alt:Boolean = false;
private var _type:String;
private var _color:uint;
private var _thick:uint;
private var _shape:String;
public function PointSprite(_point:Point, _type:String){
type = _type; //"anchor" or "handle"
drawPoint(_point);
}
public function drawPoint(_point:Point = null):void{
if(_point) point = _point.clone();
graphics.clear();
graphics.lineStyle(_thick,_color);
graphics.beginFill(0xffffff);
if(_shape == "rect") graphics.drawRect(point.x-2, point.y-2, 4, 4);
else graphics.drawCircle(point.x, point.y, 2);
graphics.endFill();
}
public function set type(_type:String):void{
this._type = _type;
switch(_type){
case "anchor":
_color = 0x00ffff;
_thick = 1;
_shape = "rect";
break;
case "handleA":
case "handleB":
_color = 0x00ffff;
_thick = 1;
_shape = "circle";
break;
}
}
public function get type():String{
return _type;
}
public override function get x():Number{
return point.x;
}
public override function get y():Number{
return point.y;
}
}