均等に分散した /偶数のスパイラルのポイントを解くためのアルゴリズム?
-
30-09-2019 - |
質問
まず、私が何を求めているかについて視覚的なアイデアを与えるために、ここに私が見つけた最も近い結果があります(まだ私が求めているものではありません)イメージは次のとおりです。
これがサイトの参照全体です。 http://www.mathematische-basteleien.de/spiral.htm
しかし、それは私が求めている問題を正確に解決するわけではありません。非常に具体的なスパイラルアルゴリズムのポイントの配列を保存したいと思います。
- ポイントは均等に分散されています
- 360度のサイクルには均一なギャップがあります
私が間違っていなければ、最初の2つのポイントは次のとおりです。
- ポイント[0] = new Point(0,0);
- ポイント[1] = new Point(1,0);
しかし、ここからどこへ行くの?
私が提供したい唯一の議論は次のとおりです。
- 解決したいポイントの量(配列の長さ)。
- 各ポイント間の距離(ピクセルのギャップ)。
- サイクル間の距離。
私には、私が計算しなければならないのはほとんど聞こえます。スパイラル回路「(そのような用語がある場合)スパイラルに沿って均等に分布するポイントをプロットするため。
できる 2*pi*半径 あなたが思うこの計算に確実に使用されますか?
以前に行われた場合は、コードの例を表示してください!
解決
楽しい小さな問題:)
図を詳しく見ると、シーケンスが明確に記載されています。
おそらくこれらを描くための多くの解決策があります、おそらくもっとエレガントですが、ここに私のものがあります:
あなたは、hypotenuseが現在のセグメントカウント+1の平方根であり、三角形の反対側は常に1であることを知っています。
また、角度の正弦(Math.sin)は、反対側をdypotenuseで割ったものと等しいことを知っています。古いムネノニックソー(サイン、反対、hypotenuse)から、 - cah-toa。
Math.sin(angle) = opp/hyp
あなたは角度のサインの値を知っています、あなたは両側を知っていますが、あなたはまだ角度を知りませんが、あなたはそのためにアークサイン関数(Math.Asin)を使用できます
angle = Math.asin(opp/hyp)
これで、各セグメントの角度がわかっており、各ラインで増分することに注意してください。
これで、角度と半径(ヒポテン)があります。 極 に デカルト それを変換するための式 角度、半径 とペア x、y ペア。
x = Math.cos(angle) * radius;
y = Math.sin(angle) * radius;
ActionScriptソリューションを要求したため、ポイントクラスはすでにこの機能を提供しています polar() 方法。半径と角度を渡すと、ポイントオブジェクトでxとyを返します。
これがスパイラルをプロットする小さなスニペットです。マウスをY軸に移動することにより、セグメントの数を制御できます。
var sw:Number = stage.stageWidth,sh:Number = stage.stageHeight;
this.addEventListener(Event.ENTER_FRAME,update);
function update(event:Event):void{
drawTheodorus(144*(mouseY/sh),sw*.5,sh*.5,20);
}
//draw points
function drawTheodorus(segments:int,x:Number,y:Number,scale:Number):void{
graphics.clear();
var points:Array = getTheodorus(segments,scale);
for(var i:int = 0 ; i < segments; i++){
points[i].offset(x,y);
graphics.lineStyle(1,0x990000,1.05-(.05+i/segments));
graphics.moveTo(x,y);//move to centre
graphics.lineTo(points[i].x,points[i].y);//draw hypotenuse
graphics.lineStyle(1+(i*(i/segments)*.05),0,(.05+i/segments));
if(i > 0) graphics.lineTo(points[i-1].x,points[i-1].y);//draw opposite
}
}
//calculate points
function getTheodorus(segments:int = 1,scale:Number = 10):Array{
var result = [];
var radius:Number = 0;
var angle:Number = 0;
for(var i:int = 0 ; i < segments ; i++){
radius = Math.sqrt(i+1);
angle += Math.asin(1/radius);//sin(angle) = opposite/hypothenuse => used asin to get angle
result[i] = Point.polar(radius*scale,angle);//same as new Point(Math.cos(angle)*radius.scale,Math.sin(angle)*radius.scale)
}
return result;
}
これは少ない行で書かれている可能性がありますが、これを2つの関数に分割したかったのです。1つは数値の計算と、ラインの描画を扱うものです。
ここにいくつかのスクリーンショットがあります:
楽しみのために、私は処理jsを使用してこれのバージョンを追加しました ここ。少し遅くなるので、これにはChromium/Chromeをお勧めします。
これで、ここで実際にこのコードを実行できます(マウスを上下に移動します):
var totalSegments = 850,hw = 320,hh = 240,segments;
var len = 10;
points = [];
function setup(){
createCanvas(640,480);
smooth();
colorMode(HSB,255,100,100);
stroke(0);
noFill();
//println("move cursor vertically");
}
function draw(){
background(0);
translate(hw,hh);
segments = floor(totalSegments*(mouseY/height));
points = getTheodorus(segments,len);
for(var i = 0 ; i < segments ; i++){
strokeWeight(1);
stroke(255-((i/segments) * 255),100,100,260-((i/segments) * 255));
line(0,0,points[i].x,points[i].y);
// strokeWeight(1+(i*(i/segments)*.01));
strokeWeight(2);
stroke(0,0,100,(20+i/segments));
if(i > 0) line(points[i].x,points[i].y,points[i-1].x,points[i-1].y);
}
}
function getTheodorus(segments,len){
var result = [];
var radius = 0;
var angle = 0;
for(var i = 0 ; i < segments ; i++){
radius = sqrt(i+1);
angle += asin(1/radius);
result[i] = new p5.Vector(cos(angle) * radius*len,sin(angle) * radius*len);
}
return result;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.4/p5.min.js"></script>
他のヒント
ジョージの答えは素晴らしかったです!私はかなり長い間解決策を探していました。
PHPのために調整された同じコードが、誰かに役立つ場合に備えています。スクリプトを使用して、x、y座標付きのマップにドット(=都市)を描画します。 xは左から始まり、yは左下から始まります。
<?
/**
* Initialize variables
**/
// MAXIMUM width & height of canvas (X: 0->400, Y: 0->400)
$width = 400;
// For loop iteration amount, adjust this manually
$segments = 10000;
// Scale for radius
$radiusScale = 2;
// Draw dot (e.g. a city in a game) for every N'th drawn point
$cityForEveryNthDot = 14;
/**
* Private variables
**/
$radius = 0;
$angle = 0;
$centerPoint = $width/2;
/**
* Container print
**/
print("<div style=\"width: ${width}px; height: ${width}px; background: #cdcdcd; z-index: 1; position: absolute; left: 0; top: 0;\"></div>");
/**
* Looper
**/
for($i=0;$i<$segments;$i++) {
// calculate radius and angle
$radius = sqrt($i+1) * $radiusScale;
$angle += asin(1/$radius);
// skip this point, if city won't be created here
if($i % $cityForEveryNthDot != 0) {
continue;
}
// calculate X & Y (from top left) for this point
$x = cos($angle) * $radius;
$y = sin($angle) * $radius;
// print dot
print("<div style=\"width: 1px; height: 1px; background: black; position: absolute; z-index: 2; left: " . round($x+$centerPoint) . "; top: " . round($y+$centerPoint) . ";\"></div>");
// calculate rounded X & Y (from bottom left)
$xNew = round($x+$centerPoint);
$yNew = round($width - ($y+$centerPoint));
// just some internal checks
if($xNew > 1 && $yNew > 1 && $xNew < $width && $yNew < $width) {
/**
* do something (e.g. store to database). Use xNew and yNew
**/
}
}