Flex4でマウス座標から3次ベジエ曲線を描く
マウス座標で制御点を決めて3次ベジエ曲線を描く。
Spriteの扱い方, addChild, Bindableとか勉強になった。
♥0 |
Line 96 |
Modified 2011-01-29 13:28:28 |
MIT License
archived:2017-03-09 12:46:46
ActionScript3 source code
/**
* Copyright etorov ( http://wonderfl.net/user/etorov )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/xjXe
*/
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
/* 4点を指定してベジエ曲線を描くサンプル
* OpenGL/GLUT のソースコードがベースでdisplay()で消して描くを繰り返してます。ので(?)すごく重い。。。
* メモ:
* * AS3での円のプロットの仕方 => beginFill()->drawCircle->endFill (参照: getCircle())
* * FlexでのSpriteのaddChildの仕方 => <s:SpriteVisualElement> (参照: myCanvas)
* * 複数のSpriteの管理の仕方 => Vector.<Sprite>をメンバ変数で。 (参照: inputDot, PlotDot)
* * Bindableの使い方 => バインド用変数を用意・[Bindable]を変数定義の前に付けて、変更するときにバインド用
* 変数を更新。コンポーネントでは{}で囲って使う (参照: currentInputDotNum, currentStartPointPos)
*/
/* 定義 */
/* マウスの座標を入れるベクトルと、その座標にプロットする点を入れるベクトル */
private var pt:Vector.<Point>=new Vector.<Point>();
private var inputDot:Vector.<Sprite>=new Vector.<Sprite>();
[Bindable]
private var currentInputDotNum:int=pt.length;
/* 最初の制御点の番号 */
private var startPoint:int=0;
[Bindable]
private var currentStartPointPos:int=startPoint;
/* 線となる点を入れるベクトル。座標はdisplay()が呼び出されたときに計算して決める */
private var plotDot:Vector.<Sprite>=new Vector.<Sprite>();
/* 道具 */
/* 点を返す関数 */
private function getCircle(radius:int):Sprite{
var sp:Sprite = new Sprite;
var g:Graphics = sp.graphics;
g.beginFill(0);
g.drawCircle(0, 0, radius);
g.endFill();
return sp;
}
/* 表示用関数 */
protected function display():void
{
var i:int;
/* display()が呼び出されるたびに座標のベクトルが初期化される */
var c:Vector.<Point>=new Vector.<Point>();
/* 1. 今までの制御点のプロットを消す */
for(i=0; i<inputDot.length; i++){
myCanvas.removeChild(inputDot[i]);
}
/* 2. 制御点の座標(マウスで今まで指定してきたもの)に点をプロットするように準備する */
for(i=0; i<pt.length;i++){
var sp:Sprite=getCircle(10);
sp.x=pt[i].x; sp.y=pt[i].y;
inputDot.push(sp);
}
/* 3. 制御点をプロット */
for(i=0; i<inputDot.length; i++){
myCanvas.addChild(inputDot[i]);
}
if(inputDot.length>3 && ((inputDot.length-1)%3)==0){
/* 1. 今までプロットした線を消す */
for(i=0; i<plotDot.length; i++){
myCanvas.removeChild(plotDot[i]);
}
/* 2. プロットする点の座標を設定 */
for(var t:Number=0; t<1.0; t+=0.001){
/* 4点から3次のベジエ曲線の座標を計算する */
c.push(
new Point(
Math.pow((1-t),3)*pt[startPoint].x + 3*t*Math.pow((1-t), 2)*pt[startPoint+1].x + 3*(1-t)*Math.pow(t, 2)*pt[startPoint+2].x + Math.pow(t, 3)*pt[startPoint+3].x,
Math.pow((1-t),3)*pt[startPoint].y + 3*t*Math.pow((1-t), 2)*pt[startPoint+1].y + 3*(1-t)*Math.pow(t, 2)*pt[startPoint+2].y + Math.pow(t, 3)*pt[startPoint+3].y
));
}
startPoint+=3;
currentStartPointPos=startPoint;
/* 3. 点のプロットの準備 */
for(i=0; i<c.length; i++){
var sp2:Sprite=getCircle(2);
sp2.x=c[i].x; sp2.y=c[i].y;
plotDot.push(sp2);
}
/* 4. 点をプロット */
for(i=0; i<plotDot.length; i++){
myCanvas.addChild(plotDot[i]);
}
}
}
/* リアクションする関数 */
protected function drawArea_clickHandler(event:MouseEvent):void
{
pt.push(new Point(event.localX,event.localY));
currentInputDotNum=pt.length;
display();
}
protected function clear_clickHandler(event:MouseEvent):void
{
var i:int=0;
/* 制御点を消す */
for(i=0;i<inputDot.length;i++){
myCanvas.removeChild(inputDot[i]);
}
inputDot=new Vector.<Sprite>();
currentInputDotNum=inputDot.length;
/* 制御点の座標を初期化 */
pt=new Vector.<Point>();
/* 開始制御点を0番目にする */
startPoint=0;
currentStartPointPos=startPoint;
/* 線を消す */
for(i=0;i<plotDot.length;i++){
myCanvas.removeChild(plotDot[i]);
}
plotDot=new Vector.<Sprite>();
/* 線の座標を初期化 */
/* for, if のすべての条件を満たさないので、displayでのベクトルcだけ初期化される */
display();
}
]]>
</fx:Script>
<s:VGroup x="10" y="10">
<s:BorderContainer id="drawArea" height="400" width="400" click="drawArea_clickHandler(event)">
<s:SpriteVisualElement id="myCanvas"/> <!-- SpriteVisualElement ではonClickイベントが送出されない? -->
</s:BorderContainer>
<s:HGroup>
<s:Button label="クリア" id="clear" click="clear_clickHandler(event)"/>
<s:Label id="currentInputDot" text="現在の制御点の数: {currentInputDotNum}" baselineShift="-5"/>
<s:Label id="currentStartPoint" text="曲線の最初の制御点の番号: {currentStartPointPos+1}" baselineShift="-5"/>
</s:HGroup>
</s:VGroup>
</s:Application>