ルーローの多角形
2n+1 角形に拡張
幅と高さからあるべき中心位置を逆算してみた
◆定幅図形の生成◆
先日、NHKの高校講座の数学で、「ルーローの三角形」を知り再現してみるテスト。
ロータリーエンジンの原理とか、7角形でイギリスのコインとかで使われてる図形。
参考:http://ja.wikipedia.org/wiki/%E3%83%AB%E3%83%BC%E3%83%AD%E3%83%BC%E3%81%AE%E4%B8%89%E8%A7%92%E5%BD%A2
四角形の穴を開けれるドリルを作れるそうなので、ドリルの動きを再現。
※厳密には三角形の公転軌道は円ではなく、楕円になるらしいけど、計算が理解できず断念。。。
参考:http://www.geocities.jp/ikuro_kotaro/koramu/322_drill4.htm
でも正円でもそれっぽく動いてる。
(ほぼ正方形の残像が確認できる)
/**
* Copyright keno42 ( http://wonderfl.net/user/keno42 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wnYz
*/
// 2n+1 角形に拡張
// forked from keno42's forked from: 定幅図形(ルーローの三角形)
// 幅と高さからあるべき中心位置を逆算してみた
// forked from sakusan393's 定幅図形(ルーローの三角形)
/*
◆定幅図形の生成◆
先日、NHKの高校講座の数学で、「ルーローの三角形」を知り再現してみるテスト。
ロータリーエンジンの原理とか、7角形でイギリスのコインとかで使われてる図形。
参考:http://ja.wikipedia.org/wiki/%E3%83%AB%E3%83%BC%E3%83%AD%E3%83%BC%E3%81%AE%E4%B8%89%E8%A7%92%E5%BD%A2
四角形の穴を開けれるドリルを作れるそうなので、ドリルの動きを再現。
※厳密には三角形の公転軌道は円ではなく、楕円になるらしいけど、計算が理解できず断念。。。
参考:http://www.geocities.jp/ikuro_kotaro/koramu/322_drill4.htm
でも正円でもそれっぽく動いてる。
(ほぼ正方形の残像が確認できる)
*/
package {
import com.bit101.components.HSlider;
import com.bit101.components.Label;
import flash.geom.Matrix;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
import flash.geom.Point;
[SWF(width=465,height=465,backgroundColor=0,frameRate=60)]
public class ReuleauxTriangle extends Sprite{
private var _points:Array = [];
private var _curvePoints:Array = [];
private var _centerPoint:Point;
private var _maxPoint:int = 3;
private var _radius:int = 100;
private var _a:Number = _radius * Math.sqrt(3);
private var _containerSp:Sprite;
private var _hSlider:HSlider;
private var _labelHSlider:Label;
private var _hSlider2:HSlider;
private var _labelHSlider2:Label;
private var _hSlider3:HSlider;
private var _labelHSlider3:Label;
private var _hSlider4:HSlider;
private var _labelHSlider4:Label;
private var _countAngleIndex:int= 2;
private var _countAngle:int = 0;
private var _bm:Bitmap;
private var _bmd:BitmapData;
private var _rotationRadius:int = 60;
private var _proportion:Number = 0.333333333;
private var _bmpColoerTrans:ColorTransform;
private const CURVE_STEP:int = 30;
public function ReuleauxTriangle(){
super();
this.addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event):void{
stage.align = StageAlign.LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.quality = StageQuality.MEDIUM;
_bmpColoerTrans = new ColorTransform(0.9,0.99,0.999999);
_bm = new Bitmap();
_bmd = new BitmapData(465,465,false,0x0);
_bm.bitmapData = _bmd;
addChild(_bm);
_containerSp = new Sprite()
_containerSp.x = stage.stageWidth/2;
_containerSp.y = stage.stageHeight/2;
_centerPoint = new Point(0, 0);
setSlider();
drawFig();
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
stage.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
}
private function downHandler(e:MouseEvent):void{
_bmd.fillRect(_bmd.rect, 0x0);
}
private function enterFrameHandler(e:Event):void{
_bmd.draw(this,null,null);
_bmd.colorTransform(_bmd.rect,_bmpColoerTrans);
if(!_containerSp.parent) addChild(_containerSp);
_containerSp.rotation += _countAngleIndex*_proportion;
//_countAngle += -_countAngleIndex;
//_containerSp.x = Math.cos(_countAngle*Math.PI/180) * _rotationRadius + stage.stageWidth/2;
//_containerSp.y = Math.sin(_countAngle*Math.PI/180) * _rotationRadius + stage.stageHeight/2;
var angle:Number = _containerSp.rotation;
angle = (angle + 360) % (360 / _maxPoint);
if ( angle < ( 90 / _maxPoint ) ) {
_containerSp.x = 0.5 * _a - _radius * Math.cos( angle * Math.PI / 180 );
_containerSp.y = - (_a * 0.5 - _radius * Math.cos( (angle- (90/_maxPoint)) * Math.PI / 180 ) );
} else if ( angle < ( 180 / _maxPoint ) ) {
_containerSp.x = - (_a * 0.5 - _radius * Math.cos( (angle-(180/_maxPoint)) * Math.PI / 180 ) );
_containerSp.y = - (_a * 0.5 - _radius * Math.cos( (angle- (90/_maxPoint)) * Math.PI / 180 ) );
} else if ( angle < ( 270 / _maxPoint ) ) {
_containerSp.x = - (_a * 0.5 - _radius * Math.cos( (angle-(180/_maxPoint)) * Math.PI / 180 ) );
_containerSp.y = ( _a * 0.5 - _radius * Math.cos( (angle- (270/_maxPoint)) * Math.PI / 180 ) );
} else {
_containerSp.x = 0.5 * _a - _radius * Math.cos( (angle-(360/_maxPoint)) * Math.PI / 180 );
_containerSp.y = ( _a * 0.5 - _radius * Math.cos( (angle- (270 / _maxPoint)) * Math.PI / 180 ) );
}
_containerSp.x += stage.stageWidth/2;
_containerSp.y += stage.stageHeight/2;
}
private function drawFig():void{
setPoint();
createCurveTo();
createLineTo();
}
//コントロール用のスライダー定義
private function setSlider():void {
// 横方向スライダー:定幅図の画数
_hSlider = new HSlider(this, 20, 20);
_hSlider.addEventListener(Event.CHANGE, onHSliderChange);
_labelHSlider = new Label(this, 20, 30);
_labelHSlider.text = "fig polygon:3";
_hSlider.maximum = 19;
_hSlider.minimum = 3;
/*
// 横方向スライダー2:円軌道の半径
_hSlider2 = new HSlider(this, 20, 50);
_hSlider2.addEventListener(Event.CHANGE, onHSliderChange2);
_labelHSlider2 = new Label(this, 20, 60);
_hSlider2.maximum = 200;
_hSlider2.minimum = 0;
_hSlider2.value = _rotationRadius;
_labelHSlider2.text = "revolution radius:60";
*/
// 横方向スライダー3:回転速度
_hSlider3 = new HSlider(this, 20, 50);
_hSlider3.addEventListener(Event.CHANGE, onHSliderChange3);
_labelHSlider3 = new Label(this, 20, 60);
_hSlider3.maximum = 10000000000;
_hSlider3.minimum = 0;
_hSlider3.value = 3333333333;
_labelHSlider3.text = "rotation speed:0.333333333";
// 横方向スライダー4:図形の半径
_hSlider4 = new HSlider(this, 20, 80);
_hSlider4.addEventListener(Event.CHANGE, onHSliderChange4);
_labelHSlider4 = new Label(this, 20, 90);
_hSlider4.maximum = 300;
_hSlider4.minimum = 100;
_labelHSlider4.text = "fig radius:100";
}
private function onHSliderChange(e:Event):void{
trace(_hSlider.value %2);
_bmd.fillRect(_bmd.rect , 0x0);
var index:int;
if(Math.floor(_hSlider.value)%2 == 0) {
index = _hSlider.value -1;
}else{
index = _hSlider.value;
}
_labelHSlider.text = "polygon index:"+String(index);
_maxPoint = index;
_a = 2 * _radius * Math.sin( Math.PI * Math.floor(_maxPoint / 2) / _maxPoint );
drawFig();
}
private function onHSliderChange2(e:Event):void{
_bmd.fillRect(_bmd.rect , 0x0);
_labelHSlider2.text = "revolution radius:" +_hSlider2.value; ;
_rotationRadius = _hSlider2.value;
}
private function onHSliderChange3(e:Event):void{
_bmd.fillRect(_bmd.rect , 0x0);
_labelHSlider3.text = "rotation speed:"+_hSlider3.value/10000000000;
_proportion = _hSlider3.value/10000000000;
}
private function onHSliderChange4(e:Event):void{
_bmd.fillRect(_bmd.rect , 0x0);
_labelHSlider4.text = "fig radius:"+_hSlider4.value;
_radius = _hSlider4.value;
_a = 2 * _radius * Math.sin( Math.PI * Math.floor(_maxPoint / 2) / _maxPoint );
// _a = _radius * Math.sqrt(3);
drawFig();
}
private function setPoint():void{
_points = [];
_curvePoints = [];
var totalInteriorAngle:int = 180 * (_maxPoint -2);
var angle:Number = 360 / _maxPoint;
var i:int;
for(i = 0; i < _maxPoint; i++){
var dx:Number = _radius*Math.cos(angle * i * Math.PI/180) + _centerPoint.x;
var dy:Number = _radius*Math.sin(angle * i * Math.PI/180) + _centerPoint.y;
_points.push(new Point(dx,dy));
};
var distIndex:int = (_maxPoint/2 | 0) + 1;
var rRadius:Number = Point.distance(_points[0],_points[distIndex]);
for(i = 0; i < _maxPoint; i++){
var cangle:Number = 360 / _maxPoint;
var nextIndex:int;
nextIndex = distIndex + i;
if(nextIndex>_maxPoint-1) nextIndex -= _maxPoint;
var offsetAngle:Number = Math.atan2(_points[i].y - _points[nextIndex].y , _points[i].x - _points[nextIndex].x);
var addAngle:Number = totalInteriorAngle/_maxPoint/(_maxPoint-2)/2;
var rAngle:Number = offsetAngle + Math.PI/180 * addAngle;
var cdx:Number = rRadius*Math.cos(rAngle) + _centerPoint.x + (_points[nextIndex].x - _centerPoint.x);
var cdy:Number = rRadius*Math.sin(rAngle) + _centerPoint.y + (_points[nextIndex].y - _centerPoint.y);
_curvePoints.push(new Point(cdx,cdy));
}
}
//基本となる正図形を描画
private function createLineTo():void{
_containerSp.graphics.lineStyle(1,0xEEEEFF);
_containerSp.graphics.moveTo(_points[0].x,_points[0].y);
var i:int;
for(i = 1; i < _maxPoint; i++){
_containerSp.graphics.lineTo(_points[i].x, _points[i].y);
}
_containerSp.graphics.lineTo(_points[0].x,_points[0].y);
}
//定幅図形を描画
private function createCurveTo():void{
_containerSp.graphics.clear();
/*
//ベジェ曲線用のポイントを描画
for(var i:int = 0; i < _curvePoints.length; i++){
_containerSp.graphics.beginFill(0xFF0000);
_containerSp.graphics.drawCircle(_curvePoints[i].x,_curvePoints[i].y,5);
_containerSp.graphics.endFill();
}
*/
_containerSp.graphics.beginFill(0xFF0000);
_containerSp.graphics.drawCircle(_centerPoint.x,_centerPoint.y,5);
_containerSp.graphics.endFill();
//カーブ曲線でつなぐ
_containerSp.graphics.lineStyle(2, 0x00FFFF);
for (var i:int = 0; i < _maxPoint; i++) {
var point:Point = new Point(_points[(i+Math.floor(_maxPoint/2))%_maxPoint].x - _points[i].x, _points[(i+Math.floor(_maxPoint/2))%_maxPoint].y - _points[i].y);
_containerSp.graphics.moveTo(point.x+_points[i].x, point.y+_points[i].y);
var matrix:Matrix = new Matrix();
matrix.rotate(Math.PI / _maxPoint / CURVE_STEP);
for ( var j:int = 0; j < CURVE_STEP; j++ ) {
point = matrix.transformPoint(point);
_containerSp.graphics.lineTo(point.x+_points[i].x,point.y+_points[i].y);
}
//_containerSp.graphics.curveTo(_curvePoints[i-1].x,_curvePoints[i-1].y,_points[i].x, _points[i].y);
}
//_containerSp.graphics.curveTo(_curvePoints[i-1].x,_curvePoints[i-1].y,_points[0].x,_points[0].y);
}
}
}