サークル錯視アニメーションを作成する


84

あなたの仕事はこのサークル錯視をアニメーション化することです。点は円の内側を回転しているように見えますが、実際には直線で動いています。

enter image description here

基準

  • 結果をアニメーション化する必要があります。アニメーションを行う方法は無関係で、を生成.gifでき、ウィンドウ、デバイス画面などに描画できます。
  • これは人気のコンテストなので、プログラムにいくつかの追加機能を追加して、ポイント数を変えるなど、より多くの賛成票を獲得できます。
  • 勝者は、最後の有効な提出の7日後に最も支持された有効な回答です。
  • 他の方法ではなく、直線上を移動するポイントを実際に実装する回答がより歓迎されます

「勝者は、7日後の最も有効な投票者です」。だから誰かが星が死ぬまで6日ごとに何かを投稿した場合、我々は勝者がありませんか?
ケビンL 14

3
@KevinLは起こりそうにないので、この質問から得られるすべての賛成票が6日ごとにトップにぶつかるのに比べて、15人の余分な担当者はそれほど重要ではないと思います。
マーティンエンダー14

1
一部の人々はこれらだけで仕事を得るために...行うと時々私は疑問に思う
ダニエルPendergast

3
「それは円の内部で回転するポイントのように見えますが、彼らは実際には直線で移動している。」、または、多分彼らは本当に円内に回転していると思われる直線で移動する...
コアダンプ

1
このアニメーションを取得することはできません..私の心から..特に3ポイントバージョン!
トーマス14

回答:


126

Python 3.4

turtleモジュールを使用します。カメは色が異なり、常に同じ方向を向いているため、カメの1つに焦点を合わせるだけで、直線に沿って動いていることが簡単にわかります。それにもかかわらず、円錯覚はまだ強いです。

11匹のカメ

わずか3匹または4匹のカメでさえ、幻想は依然として非常に強いようです。

3匹のカメ4匹のカメ

これらのGIFの例はすべてフレームレートが大幅に削減されていますが、錯覚を損なうようには見えません。コードをローカルで実行すると、アニメーションがよりスムーズになります。

import turtle
import time
from math import sin, pi
from random import random


def circle_dance(population=11, resolution=480, loops=1, flip=0, lines=0):
    population = int(population)
    resolution = int(resolution)
    radius = 250
    screen = turtle.Screen()
    screen.tracer(0)
    if lines:
        arrange_lines(population, radius)
    turtles = [turtle.Turtle() for i in range(population)]
    for i in range(population):
        dancer = turtles[i]
        make_dancer(dancer, i, population)
    animate(turtles, resolution, screen, loops, flip, radius)


def arrange_lines(population, radius):
    artist = turtle.Turtle()
    for n in range(population):
        artist.penup()
        artist.setposition(0, 0)
        artist.setheading(n / population * 180)
        artist.forward(-radius)
        artist.pendown()
        artist.forward(radius * 2)
    artist.hideturtle()


def make_dancer(dancer, i, population):
    dancer.setheading(i / population * 180)
    dancer.color(random_turtle_colour())
    dancer.penup()
    dancer.shape('turtle')
    dancer.turtlesize(2)


def random_turtle_colour():
    return random() * 0.9, 0.5 + random() * 0.5, random() * 0.7


def animate(turtles, resolution, screen, loops, flip, radius):
    delay = 4 / resolution      # 4 seconds per repetition
    while True:
        for step in range(resolution):
            timer = time.perf_counter()
            phase = step / resolution * 2 * pi
            draw_dancers(turtles, phase, screen, loops, flip, radius)
            elapsed = time.perf_counter() - timer
            adjusted_delay = max(0, delay - elapsed)
            time.sleep(adjusted_delay)


def draw_dancers(turtles, phase, screen, loops, flip, radius):
    population = len(turtles)
    for i in range(population):
        individual_phase = (phase + i / population * loops * pi) % (2*pi)
        dancer = turtles[i]
        if flip:
            if pi / 2 < individual_phase <= 3 * pi / 2:
                dancer.settiltangle(180)
            else:
                dancer.settiltangle(0)
        distance = radius * sin(individual_phase)
        dancer.setposition(0, 0)
        dancer.forward(distance)
    screen.update()


if __name__ == '__main__':
    import sys
    circle_dance(*(float(n) for n in sys.argv[1:]))

対照的に、実際に回転するものがいくつかあります:

23匹のカメ三つ葉の亀

...または彼らは?

コードは、人口、解像度、ループ、フリップ、ラインの5つのオプション引数で実行できます。

  • population カメの数です
  • resolution 時間解像度(繰り返しごとのアニメーションフレームの数)
  • loops亀が自分自身にループバックする回数を決定します。デフォルトの1は標準の円を与え、他の奇数は亀の糸のループの数を与え、偶数は両端で切断された亀の糸を与えますが、それでも曲線運動の錯覚を持ちます。
  • flipゼロ以外の場合、タートルは戻り旅行の方向を反転させます(アスラムが示唆するように、タートルは決して後方に移動しません)。デフォルトでは、エンドポイントでの視覚的な混乱を避けるために、固定方向を維持します。
  • lines 問題のサンプル画像との一貫性を保つために、カメが移動する線がゼロ以外の場合に表示されます。

flipsetを使用した場合と使用しない場合の例lines。私は散発的なジャンプを好まないので、上記のメイン例をフリップなしで残しましたが、円の端はすべてのカメを揃えるとより滑らかに見えるので、実行時に好きなスタイルを選択できるオプションがありますコード。

フリップとラインを持つ11匹のカメ11羽のカメ

上記の画像がすべてこの同じコードからどのように生成されたかは、すぐには明らかではないかもしれません。特に、外側の遅いループと内側の速いループ(誰かが誤って落としてしまったカーディオイドのように見えるもの)を持つ、さらに上にある画像。実験/思考中に発見を遅らせたい人のために、この説明を下に隠しました。

ループの数を15に設定し、タートルの数を23(15のループを表すには低すぎる)のままにして、サイズの異なる内側と外側のループを持つアニメーションを作成しました。多数のカメを使用すると、15個の明確に定義されたループが生成されます。使用するカメの数が少なすぎると、エイリアシングが発生します(画像処理およびレンダリングと同じ理由で)。高すぎる周波数を表現しようとすると、歪みのある低い周波数が表示されます。

別の数字を試してみると、これらの歪みのいくつかはより対称的なオリジナルよりも興味深いことがわかったので、ここに1つを含めたいと思いました...


18
私は亀が好きです。
FreeAsInBeer 14

18
私はカメの+1を砲撃しました
MrEngineer13 14

@ProgramFOX構文の強調表示に感謝します!ヘルプとメタを検索して、コードゴルフで構文の強調表示がないことを確信しました。これで今よりも満足しています。
センモウヒラムシ

1
@aslumは簡単に変更できますが、方向を固定して、直線コースから逸脱しないことを本当に強調したかったのです。おそらく、オプションとしてコードに追加して、人々が好みのアプローチを選択できるようにする必要があります。
trichoplax 14

4
+1-マーチングバンドがこれらのファンキーなものを実行するのを見るのは素晴らしいことです!
mkoistinen 14

96

C

結果:

ここに画像の説明を入力してください

#include <stdio.h>
#include <Windows.h>
#include <Math.h>

int round (double r) { return (r > 0.0) ? (r + 0.5) : (r - 0.5); }
void print (int x, int y, char c) {
    COORD p = { x, y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), p);
    printf("%c", c);
}

int main ()
{
    float pi = 3.14159265358979323846;
    float circle = pi * 2;
    int len = 12;
    int hlen = len / 2;
    int cx = 13;
    int cy = 8;
    float w = 11.0;
    float h =  8.0;
    float step = 0.0;

    while (1)
    {
        system("cls"); // xD

        for (int i = 0; i < len; i++)
        {
            float a = (i / (float)len) * circle;
            int x = cx + round(cos(a) * w);
            int y = cy + round(sin(a) * h);
            print(x, y, 'O');

            if (i < hlen) continue;

            step -= 0.05;
            float range = cos(a + step);
            x = cx + round(cos(a) * (w - 1) * range);
            y = cy + round(sin(a) * (h - 1) * range);
            print(x, y, 'O');
        }

        Sleep(100);
    }

    return 0;
}

3
一部のフレームでは、少しオフになっています。しかし、ASCIIでおめでとうございます!
ちょうど半分14

10
ASCII +1およびsystem("cls"); // xD
ChristophBöhmwalder14年

1
美しいです。
trichoplax 14

1
これはLinux上で動作します。(かなり無残ものの)
user824294

義務的な嫌悪感のコメント:「これはCではありません!この標準では、Sleep、COORD、またはSetConsoleCursorPositionは定義されていません!」
user253751 14

52

SVG(Javascriptなし)

JSFiddleリンクはこちら

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 380 380" width="380" height="380" version="1.0">
  <g transform="translate(190 190)">
    <circle cx="0" cy="0" r="190" fill="#000"/>
    <line x1="0" y1="-190" x2="0" y2="190" stroke="#fff" stroke-width="1.5"/>
    <line x1="72.71" y1="175.54" x2="-72.71" y2="-175.54" stroke="#fff" stroke-width="1.5"/>
    <line x1="134.35" y1="134.35" x2="-134.35" y2="-134.35" stroke="#fff" stroke-width="1.5"/>
    <line x1="175.54" y1="72.71" x2="-175.54" y2="-72.71" stroke="#fff" stroke-width="1.5"/>
    <line x1="190" y1="0" x2="-190" y2="0" stroke="#fff" stroke-width="1.5"/>
    <line x1="175.54" y1="-72.71" x2="-175.54" y2="72.71" stroke="#fff" stroke-width="1.5"/>
    <line x1="134.35" y1="-134.35" x2="-134.35" y2="134.35" stroke="#fff" stroke-width="1.5"/>
    <line x1="72.71" y1="-175.54" x2="-72.71" y2="175.54" stroke="#fff" stroke-width="1.5"/>
    <g transform="rotate(0)">
      <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0" to="360" begin="0" dur="8s" repeatCount="indefinite"/>
      <g transform="translate(0 90)">
        <g transform="rotate(0)">
          <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0" to="-360" begin="0" dur="4s" repeatCount="indefinite"/>
          <circle cx="0" cy="90" r="10" fill="#fff"/>
          <circle cx="63.64" cy="63.64" r="10" fill="#fff"/>
          <circle cx="90" cy="0" r="10" fill="#fff"/>
          <circle cx="63.64" cy="-63.64" r="10" fill="#fff"/>
          <circle cx="0" cy="-90" r="10" fill="#fff"/>
          <circle cx="-63.64" cy="-63.64" r="10" fill="#fff"/>
          <circle cx="-90" cy="0" r="10" fill="#fff"/>
          <circle cx="-63.64" cy="63.64" r="10" fill="#fff"/>
        </g>
      </g>
    </g>
  </g>
</svg>

うーん、これは規則を順調に通過させると確信していますが、個人的には、あなたが実際に反対をしていることに失望しました。「点は円の内側を回転しているように見えますが、実際には直線で動いているだけです。」ではなく、あなたの実装は「点が直線で動いているように見えますが、実際にはちょうど円の内側を回転します。」
mkoistinen 14

最もスムーズな答え!
デレク朕會功夫14

14
@mkoistinenあなたの言うことはわかりますが、ポイントは本当に直線で動いています。2回の回転で位置を計算する方が簡単です:-)
squeamish ossifrage 14

すべてを「手作業」で行ったのですか、それとも何らかの(非テキスト)エディターを使用したのですか
flawr 14

5
@flawr 電話でプレーンテキストエディターと電卓を使って数字を計算しました:-)
squeamish ossifrage 14

47

http://jsfiddle.net/z6vhD/13/

intervaltimeFPSを変更します(FPS = 1000 / intervaltime)。
balls#ボールを変更します。
maxstepサイクル内の#ステップを調整すると、「スムーザー」が大きくなります。64は、滑らかに見える場所で十分に大きくなければなりません。

ボールを線に沿って動かすのではなく、円が動くようにモデル化されていますが、視覚効果は同じであるはずです。コードの一部はかなり冗長ですが、これはゴルフのコードではないため、...

var intervalTime = 40;
var balls = 8;
var maxstep = 64;

var canvas = $('#c').get(0); // 100% necessary jquery
var ctx = canvas.getContext('2d');
var step = 0;

animateWorld = function() {
    createBase();
    step = step % maxstep;
    var centerX = canvas.width/2 + 115 * Math.cos(step * 2 / maxstep * Math.PI);
    var centerY = canvas.height/2 + 115 * Math.sin(step * 2 / maxstep * Math.PI);

    for (var i=0; i<balls; i++) {
        drawCircle(ctx, (centerX + 115 * Math.cos((i * 2 / balls - step * 2 / maxstep) * Math.PI)), (centerY + 115 * Math.sin((i * 2 / balls - step * 2 / maxstep) * Math.PI)), 10, '#FFFFFF');     
    }

    step++;
}

function createBase() {
    drawCircle(ctx, canvas.width/2, canvas.height/2, 240, '#000000');
    for(var i=0; i<balls*2; i++) {
        drawLine(ctx, canvas.width/2, canvas.height/2, canvas.width/2 + 240 * Math.cos(i / balls * Math.PI), canvas.height/2 + 240 * Math.sin(i / balls * Math.PI), '#FFFFFF');
    }
}

function drawLine(context, x1, y1, x2, y2, c) {
    context.beginPath();
    context.moveTo(x1,y1);
    context.lineTo(x2,y2);
    context.lineWidth = 3;
    context.strokeStyle = c;
    context.stroke();
}

function drawCircle(context, x, y, r, c) {
    context.beginPath();
    context.arc(x, y, r, 0, 2*Math.PI);
    context.fillStyle = c;
    context.fill();
}

function drawRect(context, x, y, w, h, c) {
    context.fillStyle = c;
    context.fillRect(x, y, w, h);
}

$(document).ready(function() {
    intervalID = window.setInterval(animateWorld, intervalTime);
});

2
とても滑らかです!非常に素晴らしい。
nneonneo

5
アニメーションにsetIntervalを使用しないで、requestAnimationFrame代わりにを使用してください。 を使用してJSFiddle変更しましたrequestAnimationFrame
klingt.net 14

1
わずかなパラメーター調整で、非常に異なるものが得られます。
FreeAsInBeer 14

@KevinLうん、ちょうどそれに気づいた。更新しました。
FreeAsInBeer 14

1
@FreeAsInBeerああ、あなたが非常に異なることを言ったとき、私はあなたがjsfiddle.net/z6vhD/100
ケビンL

41

CSSアニメーション

cssアニメーションのみを使用するソリューション(JSFiddleのアニメーションを参照 -最新バージョンで動作できるように、ブラウザ固有のプレフィックスをフィドルに追加したことに注意してください)。

<body>
    <div id="w1"></div>
    <div id="w2"></div>
    <div id="w3"></div>
    <div id="w4"></div>
    <div id="w5"></div>
    <div id="w6"></div>
    <div id="w7"></div>
    <div id="w8"></div>
</body>


div {
    position: absolute;
    width: 20px;
    height: 20px;
    border-radius: 20px;
    background: red;
    animation-duration: 4s;
    animation-iteration-count: infinite;
    animation-direction: alternate;
    animation-timing-function: ease-in-out;
}

#w1 { animation-name: s1; animation-delay: 0.0s }
#w2 { animation-name: s2; animation-delay: 0.5s }
#w3 { animation-name: s3; animation-delay: 1.0s }
#w4 { animation-name: s4; animation-delay: 1.5s }
#w5 { animation-name: s5; animation-delay: 2.0s }
#w6 { animation-name: s6; animation-delay: 2.5s }
#w7 { animation-name: s7; animation-delay: 3.0s }
#w8 { animation-name: s8; animation-delay: 3.5s }

@keyframes s1 { from {top: 100px; left:   0px;} to {top: 100px; left: 200px;} } 
@keyframes s2 { from {top:  62px; left:   8px;} to {top: 138px; left: 192px;} } 
@keyframes s3 { from {top:  29px; left:  29px;} to {top: 171px; left: 171px;} } 
@keyframes s4 { from {top:   8px; left:  62px;} to {top: 192px; left: 138px;} } 
@keyframes s5 { from {top:   0px; left: 100px;} to {top: 200px; left: 100px;} } 
@keyframes s6 { from {top:   8px; left: 138px;} to {top: 192px; left:  62px;} } 
@keyframes s7 { from {top:  29px; left: 171px;} to {top: 171px; left:  29px;} } 
@keyframes s8 { from {top:  62px; left: 192px;} to {top: 138px; left:   8px;} } 

3
フィドルが最新のChromeで動作しない= /
mkoistinen

1
@mkoistinen-異なるブラウザで動作するには、異なるプレフィックスを追加する必要があります。(-webkit-Webkitベースおよび-moz-Mozillaベースの場合)更新されたプレフィックスを持つ同じフィドルがあります:jsfiddle.net/nBCxz/3
Derek朕會功夫14

@mkoistinenそのとおりです。新しいフィドルは、必要なすべてのブラウザープレフィックスを追加し、最新のChromeで動作します。
ハワード14

生のリンクテキストには閉じかっこがありません-修正したい場合に通知するだけで完全に使用できます(変更する文字が6文字未満なので、できません)。
センモウヒラムシ

35

Mathematica

これは非常に簡単な提出です。

animateCircle[n_] := Animate[Graphics[
   Flatten@{
     Disk[],
     White,
     Map[
      (
        phase = #*2 \[Pi]/n;
        line = {Cos[phase], Sin[phase]};
        {Line[{-line, line}],
         Disk[Sin[t + phase]*line, 0.05]}
        ) &,
      Range[n]
      ]
     },
   PlotRange -> {{-1.1, 1.1}, {-1.1, 1.1}}
   ],
  {t, 0, 2 \[Pi]}
  ]

電話をかけるanimateCircle[32]と、32本の線と円のきちんとしたアニメーションが得られます。

ここに画像の説明を入力してください

Mathematicaでは完全にスムーズですが、GIFのフレーム数を少し制限する必要がありました。

各行に2枚のディスクを入れるとどうなりますか?(つまり、Disk[-Sin[t + phase]*line, 0.05]内のリストに追加しますMap。)

ここに画像の説明を入力してください

また、位相を90°ずらすこともできます(Cos代わりに使用します-Sin)。

ここに画像の説明を入力してください


私はおそらくあなたが変更する必要がある、あなたは何を意味するかグリッチやる知らない{t, 0, 2 \[Pi]}{t, 0, 2 \[Pi] - 2 \[Pi]/60, 2 \[Pi]/60}が二つの同一のフレームで、変更されないようにAnimateしますTable。その後、GIFをエクスポートできるようになります。
スウィッシュ

@swishいいえ、実際には存在しないはずの奇妙な追加行と、本来あるべきではない(実際の結果にはないAnimate)ディスクをレンダリングします。Tableただし、もう一度使用してみます。
マーティンエンダー

@swishうまくいきました。私は昨日このようなことを試みたと思ったが、どうやらそうではなかったようだ。
マーティンエンダー14

25

VBScript + VBA + Excel円グラフ

これはあなたのプロセッサを少し泣かせますが、見た目はきれいで、仕様どおりに動作すると思います。@Fabricioの答えをガイドとして使用して、円運動アルゴリズムを実装しました。

編集:レンダリング速度を改善するためにいくつかの調整を行いました。

円グラフのスクリーンショット

コード:

'Open Excel
Set objX = CreateObject("Excel.Application")
objX.Visible = True
objX.Workbooks.Add

'Populate values
objX.Cells(1, 1).Value = "Lbl"
objX.Cells(1, 2).Value = "Amt"
For fillX = 2 to 17
    objX.Cells(fillX, 1).Value = "V"+Cstr(fillX-1)
    objX.Cells(fillX, 2).Value = "1"
Next

'Create pie
objX.Range("A2:B17").Select
objX.ActiveSheet.Shapes.AddChart.Select
With objX.ActiveChart
    .ChartType = 5 'pieChart
    .SetSourceData  objX.Range("$A$2:$B$17")
    .SeriesCollection(1).Select
End with    

'Format pie
With objX.Selection.Format
    .Fill.ForeColor.RGB = 0 'black
    .Fill.Solid
    .Line.Weight = 2
    .Line.Visible = 1
    .Line.ForeColor.RGB = 16777215 'white
End With

'animation variables
pi = 3.14159265358979323846
circle = pi * 2 : l  = 16.0
hlen = l / 2    : cx = 152.0
cy = 99.0       : w  = 90.0
h  = 90.0       : s  = 0.0
Dim posArry(7,1)

'Animate
While 1 
  For i = 0 to hlen-1
    a = (i / l) * circle
    range = cos(a + s)
    x = cx + cos(a) * w * range
    y = cy + sin(a) * h * range

    If whileInx = 1 Then 
        createOval x, y
    ElseIf whileInx = 2 Then 
        objX.ActiveChart.Legend.Select
    ElseIf whileInx > 2 Then
        ovalName = "Oval "+ Cstr(i+1)
        dx = x - posArry(i,0)
        dy = y - posArry(i,1)
        moveOval ovalName, dx, dy
    End if

    posArry(i,0) = x
    posArry(i,1) = y
  Next

  s=s-0.05
  wscript.Sleep 1000/60 '60fps
  whileInx = 1 + whileInx
Wend

'create circles
sub createOval(posX, posY)
    objX.ActiveChart.Shapes.AddShape(9, posX, posY, 10, 10).Select '9=oval
    objX.Selection.ShapeRange.Line.Visible = 0
    with objX.Selection.ShapeRange.Fill
       .Visible = 1
       .ForeColor.RGB = 16777215 'white
       .solid
    end with
end sub

'move circles
sub moveOval(ovalName, dx, dy)
    with objX.ActiveChart.Shapes(ovalName)      
        .IncrementLeft dx
        .IncrementTop  dy
    end with
end sub

81行目のエラー80070057、「指定された名前の要素は存在しません」またはこのようなもの(ハンガリー語から翻訳されたため、正確なエラーメッセージがわかりません)でクラッシュします。
マルツェルム14

Szervusz、@ marczellm。「アニメーション化」中にチャートの外側をクリックすると、そのエラーを再現できます。フォーカスを許可しないと、プログラムはエラーになります。それ以外の場合、これはOfficeとの非互換性による可能性があります。Win7のOffice 2010を使用しています。
comfortablydrei

Office 2007、Win7。私の場合、チャートにまったく焦点が合っていないようです。
マルツェルム14

21

Excel、161バイト

エクセル

=2*PI()*(NOW()*24*60*60/A2-FLOOR(NOW()*24*60*60/A2,1))
=ROUND(7*SIN(A1),0)
=ROUND(5*SIN(A1+1*PI()/4),0)
=ROUND(7*SIN(A1+2*PI()/4),0)
=ROUND(5*SIN(A1+3*PI()/4),0)

A2(期間)は、完全な「革命」の時間(秒)を決定します。

行内の各セルは、対応する行の値に関連する基本的な条件です。たとえば、K2は次のとおりです。

 =1*(A5=7)

そして、中央のセル(K9)は次のとおりです。

=1*OR(A5=0,A6=0,A7=0,A8=0)

ランダムセルで「削除」を押して、常に更新をトリガーすることにより、アニメーションを強制しました。

私はこれが古いトピックであることを知っていますが、最近の活動がそれをトップに持ち込み、何らかの理由で魅力的なように見えました。長時間のpcgリスナー、最初の呼び出し元。穏やかな。


うわー、それはあなたがエクセルでそれを行うことができますことを信じられないです:D
ベータ崩壊

15

PSTricksをお楽しみください。

ここに画像の説明を入力してください

\documentclass[preview,border=12pt,multi]{standalone}
\usepackage{pstricks}

\psset{unit=.3}

% static point
% #1 : half of the number of points
% #2 : ith point
\def\x[#1,#2]{(3*cos(Pi/#1*#2))}
\def\y[#1,#2]{(3*sin(Pi/#1*#2))}

% oscillated point
% #1 : half of the number of points
% #2 : ith point
% #3 : time parameter
\def\X[#1,#2]#3{(\x[#1,#2]*cos(#3+Pi/#1*#2))}
\def\Y[#1,#2]#3{(\y[#1,#2]*cos(#3+Pi/#1*#2))}

% single frame
% #1 : half of the number of points
% #2 : time parameter
\def\Frame#1#2{%
\begin{pspicture}(-3,-3)(3,3)
    \pstVerb{/I2P {AlgParser cvx exec} bind def}%
    \pscircle*{\dimexpr3\psunit+2pt\relax}
    \foreach \i in {1,...,#1}{\psline[linecolor=yellow](!\x[#1,\i] I2P \y[#1,\i] I2P)(!\x[#1,\i] I2P neg \y[#1,\i] I2P neg)}
    \foreach \i in {1,...,#1}{\pscircle*[linecolor=white](!\X[#1,\i]{#2} I2P \Y[#1,\i]{#2} I2P){2pt}}   
\end{pspicture}}

\begin{document}
\foreach \t in {0,...,24}
{   
    \preview
    \Frame{1}{2*Pi*\t/25} \quad \Frame{2}{2*Pi*\t/25} \quad \Frame{3}{2*Pi*\t/25} \quad \Frame{5}{2*Pi*\t/25} \quad \Frame{10}{2*Pi*\t/25}
    \endpreview
}
\end{document}

11

Fortran

:各フレームはでFortranのGIFモジュールを使用して、個々のGIFファイルとして作成されhttp://fortranwiki.org/fortran/show/writegif
その後、私は1つのアニメーションGIFに、個々のGIFファイルをマージするためのImageMagickを使って、少しカンニング。

Fortran

更新:new = .trueに設定します。以下を取得するには:

ここに画像の説明を入力してください

program circle_illusion

use, intrinsic :: iso_fortran_env, only: wp=>real64
use gif_util  !gif writing module from http://fortranwiki.org/fortran/show/writegif

implicit none

logical,parameter :: new = .false.

integer,parameter  :: n        = 500  !550  !size of image (square)     
real(wp),parameter :: rcircle  = n/2  !250  !radius of the big circle
integer,parameter  :: time_sep = 5    !deg

real(wp),parameter :: deg2rad = acos(-1.0_wp)/180.0_wp
integer,dimension(0:n,0:n):: pixel     ! pixel values
integer,dimension(3,0:3)  :: colormap  ! RGB 0:255 for colors 0:ncol    
real(wp),dimension(2)     :: xy
integer,dimension(2)      :: ixy
real(wp)                  :: r,t
integer                   :: i,j,k,row,col,m,n_cases,ang_sep
character(len=10)         :: istr

integer,parameter  :: black = 0
integer,parameter  :: white = 1
integer,parameter  :: red   = 2
integer,parameter  :: gray  = 3    
colormap(:,0) = [0,0,0]          !black
colormap(:,1) = [255,255,255]    !white
colormap(:,2) = [255,0,0]        !red
colormap(:,3) = [200,200,200]    !gray

if (new) then
    ang_sep = 5
    n_cases = 3
else
    ang_sep = 20
    n_cases = 0
end if

do k=0,355,time_sep

    !clear entire image:
    pixel = white      

    if (new) call draw_circle(n/2,n/2,black,n/2)  

    !draw polar grid:    
    do j=0,180-ang_sep,ang_sep
        do i=-n/2, n/2
            call spherical_to_cartesian(dble(i),dble(j)*deg2rad,xy)
            call convert(xy,row,col)
            if (new) then
                pixel(row,col) = gray
            else
                pixel(row,col) = black  
            end if  
        end do
    end do

    !draw dots:
    do m=0,n_cases
        do j=0,360-ang_sep,ang_sep
            r = sin(m*90.0_wp*deg2rad + (k + j)*deg2rad)*rcircle                
            t = dble(j)*deg2rad    
            call spherical_to_cartesian(r,t,xy)
            call convert(xy,row,col)
            if (new) then
                !call draw_circle(row,col,black,10)  !v2
                !call draw_circle(row,col,m,5)       !v2
                call draw_circle(row,col,white,10)   !v3
            else
                call draw_square(row,col,red)        !v1
            end if
        end do
    end do

    !write the gif file for this frame:        
    write(istr,'(I5.3)') k
    call writegif('gifs/test'//trim(adjustl(istr))//'.gif',pixel,colormap)

end do

!use imagemagick to make animated gif from all the frames:
! from: http://thanosk.net/content/create-animated-gif-linux
if (new) then
    call system('convert -delay 5 gifs/test*.gif -loop 0 animated.gif')
else
    call system('convert -delay 10 gifs/test*.gif -loop 0 animated.gif')
end if

!delete individual files:
call system('rm gifs/test*.gif')

contains

    subroutine draw_square(r,c,icolor)

    implicit none
    integer,intent(in) :: r,c  !row,col of center
    integer,intent(in) :: icolor

    integer,parameter :: d = 10 !square size

    pixel(max(0,r-d):min(n,r+d),max(0,c-d):min(n,c+d)) = icolor

    end subroutine draw_square

    subroutine draw_circle(r,c,icolor,d)

    implicit none
    integer,intent(in) :: r,c  !row,col of center
    integer,intent(in) :: icolor
    integer,intent(in) :: d  !diameter

    integer :: i,j

    do i=max(0,r-d),min(n,r+d)
        do j=max(0,c-d),min(n,c+d)
            if (sqrt(dble(i-r)**2 + dble(j-c)**2)<=d) &
                pixel(i,j) = icolor
        end do
    end do

    end subroutine draw_circle

    subroutine convert(xy,row,col)

    implicit none
    real(wp),dimension(2),intent(in) :: xy  !coordinates
    integer,intent(out) :: row,col

    row = int(-xy(2) + n/2.0_wp)
    col = int( xy(1) + n/2.0_wp)

    end subroutine convert

    subroutine spherical_to_cartesian(r,theta,xy)

    implicit none
    real(wp),intent(in) :: r,theta
    real(wp),dimension(2),intent(out) :: xy

    xy(1) = r * cos(theta)
    xy(2) = r * sin(theta)

    end subroutine spherical_to_cartesian

end program circle_illusion

1
私は、垂直要素と水平要素のインパクト「スキッシュ」が好きです。
ポートランドランナー14

11

必須のC64バージョン。

お気に入りのエミュレータにコピー&ペースト:

C64バージョン

1 print chr$(147)
2 poke 53281,0
3 for p=0 to 7
5 x=int(11+(cos(p*0.78)*10)):y=int(12+(sin(p*0.78)*10))
6 poke 1024+x+(y*40),15
9 next p
10 for sp=2040 to 2047:poke sp,13:next sp
20 for i=0 to 62:read a:poke 832+i,a:next i
30 for i=0 to 7:poke 53287+i,i+1:next i
40 rem activate sprites
50 poke 53269,255
60 an=0.0
70 rem maincycle
75 teta=0.0:k=an
80 for i=0 to 7
90 px=cos(k)*64
92 s=i:x=px*cos(teta): y=px*sin(teta): x=x+100: y=y+137: gosub 210
94 teta=teta+0.392699
95 k=k+0.392699
96 next i
130 an=an+0.1
140 goto 70
150 end
200 rem setspritepos
210 poke 53248+s*2,int(x): poke 53249+s*2,int(y)
220 return
5000 data 0,254,0
5010 data 3,199,128
5020 data 7,0,64
5030 data 12,126,96
5040 data 25,255,48
5050 data 59,7,152
5060 data 52,1,200
5070 data 116,0,204
5080 data 120,0,100
5090 data 120,0,100
5100 data 120,0,100
5110 data 120,0,36
5120 data 104,0,36
5130 data 100,0,108
5140 data 54,0,72
5150 data 51,0,152
5160 data 25,131,16
5170 data 12,124,96
5180 data 4,0,64
5190 data 3,1,128
5200 data 0,254,0

10

デフォルトの設定を別の何かに変更するコンパクトなJavaScriptバージョン

http://jsfiddle.net/yZ3DP/1/

HTML:

<canvas id="c" width="400" height="400" />

JavaScript:

var v= document.getElementById('c');
var c= v.getContext('2d');
var w= v.width, w2= w/2;
var num= 28, M2= Math.PI*2, da= M2/num;
draw();
var bw= 10;
var time= 0;
function draw()
{
    v.width= w;
    c.beginPath();
    c.fillStyle= 'black';
    circle(w2,w2,w2);
    c.lineWidth= 1.5;
    c.strokeStyle= c.fillStyle= 'white';
    var a= 0;
    for (var i=0; i< num*2; i++){
        c.moveTo(w2,w2);
        c.lineTo(w2+Math.cos(a)*w2, w2+Math.sin(a)*w2);
        a+= da/2;
    }
    c.stroke();
    a= 0;
    for (var i=0; i< num; i++){
        circle(w2+Math.cos(a)*Math.sin(time+i*Math.PI/num)*(w2-bw), 
               w2+Math.sin(a)*Math.sin(time+i*Math.PI/num)*(w2-bw), bw);
        a+= da/2;
    }
    time+=0.03;
   requestAnimationFrame(draw);
}

function circle(x,y,r)
{
    c.beginPath();
    c.arc(x, y, r, 0, M2);
    c.fill();

}

2
あなたは... ドーナツを作りましたか?実際、あなたのアニメーションは小さなドットできれいに見えます(試してみてくださいbw=10)。回答を編集してコードを表示してください。あなたはそれでいる間ああ、そして、あなたは修正する必要がありますバグがあります:置き換えるtime+i*0.39*0.29time+i*Math.PI/num座標は、任意の値を正しく計算されるように、三角関数の計算にnum。(PSはここでJSFiddleを更新しました。codegolf.stackexchange.comへようこそ)
squeamish ossifrage 14

何か違うものを作りたかっただけです(カメのようなもの)。ここでcodegolfの初心者:)ああ、そして式:DIに感謝します。急いでランダム値を試してみました。正しい式にたどり着くまでに止めませんでした:P
Diego

1
ちょっとした視覚的な楽しみのための+1小さな変更:http : //jsfiddle.net/9TQrm/またはhttp://jsfiddle.net/Wrqs4/1/
ポートランドランナー14

4

エルムと一緒に。私は、このソリューション(GitHub)を改善するためにPRを喜んで受け入れる完全な初心者です。

ここに画像の説明を入力してください

この投稿は実際に直線上のポイントを移動していることに注意してください。

import Color exposing (..)
import Graphics.Collage exposing (..)
import Graphics.Element exposing (..)
import Time exposing (..)
import Window
import List exposing (..)
import AnimationFrame -- "jwmerrill/elm-animation-frame"
import Debug

-- CONFIG

size = 600
circleSize = 240
dotCount = 12
dotSize = 10
velocity = 0.01

-- MODEL

type alias Dot =
    { x : Float
    , angle : Float
    }

type alias State = List Dot

createDots : State
createDots = map createDot [ 0 .. dotCount - 1 ]

createDot : Int -> Dot
createDot index =
    let angle = toFloat index * pi / dotCount
    in { x = 0
       , angle = angle
       }

-- UPDATE

update : Time -> State -> State
update time dots = map (moveDot time) dots |> Debug.watch "Dots"

moveDot : Time -> Dot -> Dot
moveDot time dot =
  let t = velocity * time / pi
      newX = (-circleSize + dotSize) * cos(t + dot.angle)
  in { dot | x <- newX }

-- VIEW

view : State -> Element
view dots =
   let background = filled black (circle circleSize)
       dotLinePairs = map viewDotWithLine dots
   in collage size size (background :: dotLinePairs)

viewDotWithLine : Dot -> Form
viewDotWithLine dot =
  let dotView = viewDot dot
      lineView = createLineView
  in group [dotView , lineView] |> rotate dot.angle

viewDot : Dot -> Form
viewDot d = alpha 0.8 (filled lightOrange (circle dotSize)) |> move (d.x, 0)

createLineView : Form
createLineView = traced (solid white) (path [ (-size / 2.0, 0) , (size / 2.0, 0) ])

-- SIGNALS

main = Signal.map view (animate createDots)

animate : State -> Signal State
animate dots = Signal.foldp update dots time

time = Signal.foldp (+) 0 AnimationFrame.frame

4
そのカーソルは私をうまくだましました、そして、私のものは黒またはそのサイズでさえありません。
コール

2

Second Life LSL

アニメーション タートルアルファ画像の開始(画像を保存するには下を右クリック)
turtle.png
タートルアルファ画像の終了(画像を保存するには上を右クリック)

オブジェクトの作成:
ルートプリムシリンダーサイズを<1、1、0.01>スライス0.49、0.51、カラー< 0、0、0>
このシリンダーの説明を引用符なしで「8,1,1,1」にします(非常に重要)
シリンダーを作成し、「cyl」と名付けます。色< 0.25、0.25、0.25 >アルファ0.5を
複製しますCYL 48回
箱を作り、トップ透明度0を除いて、「球」色<1、1、1>透明度100をそれに名前を付けるには
ボックスの顔0であなたの亀のテクスチャを入れ、カメは+ X直面する必要があります
ボックスを複製48回
すべてのボックスとシリンダーを選択し、最後にルートシリンダーを選択してください。リンク(コントロールL)

これらの2つのスクリプトをルートに配置します。

//script named "dialog"
default
{
    state_entry()
    {

    }

    link_message(integer link, integer num, string msg, key id)
    {
        list msgs = llCSV2List(msg);
        key agent = (key)llList2String(msgs, 0);
        string prompt = llList2String(msgs, 1);
        integer chan = (integer)llList2String(msgs, 2);
        msgs = llDeleteSubList(msgs, 0, 2);
        llDialog(agent, prompt, msgs, chan);
    }
}

//script named "radial animation"
float interval = 0.1;
float originalsize = 1.0;
float rate = 5;
integer maxpoints = 48;
integer points = 23; //1 to 48
integer multiplier = 15;
integer lines;
string url = "https://codegolf.stackexchange.com/questions/34887/make-a-circle-illusion-animation/34891";

list cylinders;
list spheres;
float angle;
integer running;
integer chan;
integer lh;

desc(integer on)
{
    if(on)
    {
        string desc = 
            (string)points + "," +
            (string)multiplier + "," +
            (string)running + "," +
            (string)lines
            ;

        llSetLinkPrimitiveParamsFast(1, [PRIM_DESC, desc]);
    }
    else
    {
        list params = llCSV2List(llList2String(llGetLinkPrimitiveParams(1, [PRIM_DESC]), 0));
        points = (integer)llList2String(params, 0);
        multiplier = (integer)llList2String(params, 1);
        running = (integer)llList2String(params, 2);
        lines = (integer)llList2String(params, 3);
    }    
}

init()
{
    llSetLinkPrimitiveParamsFast(LINK_ALL_OTHERS, [PRIM_POS_LOCAL, ZERO_VECTOR, 
        PRIM_COLOR, ALL_SIDES, <1, 1, 1>, 0]);
    integer num = llGetNumberOfPrims();
    integer i;
    for(i = 2; i <= num; i++)
    {
        string name = llGetLinkName(i);

        if(name == "cyl")
            cylinders += [i];
        else if(name == "sphere")
            spheres += [i];
    }  

    vector size = llGetScale();
    float scale = size.x/originalsize;

    float r = size.x/4;
    vector cylindersize = <0.01*scale, 0.01*scale, r*4>;
    float arc = 180.0/points;

    for(i = 0; i < points; i++)
    {
        float angle = i*arc;
        rotation rot = llEuler2Rot(<0, 90, 0>*DEG_TO_RAD)*llEuler2Rot(<0, 0, angle>*DEG_TO_RAD);

        integer cyl = llList2Integer(cylinders, i);
        integer sphere = llList2Integer(spheres, i);

        llSetLinkPrimitiveParamsFast(1, [PRIM_LINK_TARGET, cyl, PRIM_POS_LOCAL, ZERO_VECTOR, PRIM_ROT_LOCAL, rot, PRIM_SIZE, cylindersize, PRIM_COLOR, ALL_SIDES, <0.25, 0.25, 0.25>, 0.5*lines,
        PRIM_LINK_TARGET, sphere, PRIM_COLOR, ALL_SIDES, <0.25 + llFrand(0.75), 0.25 + llFrand(0.75), 0.25 + llFrand(0.75)>, 1
        ]);
    }
}

run()
{
    vector size = llGetScale();
    float scale = size.x/originalsize;

    float r = size.x/2;
    vector spheresize = <0.06, 0.06, 0.02>*scale;
    float arc = 180.0/points;
    list params;
    integer i;
    for(i = 0; i < points; i++)
    {

        float x = r*llCos((angle + i*arc*multiplier)*DEG_TO_RAD);

        vector pos = <x, 0, 0>*llEuler2Rot(<0, 0, i*arc>*DEG_TO_RAD);
        rotation rot = llEuler2Rot(<0, 0, i*arc>*DEG_TO_RAD);
        integer link = llList2Integer(spheres, i);
        params += [PRIM_LINK_TARGET, link, PRIM_POS_LOCAL, pos,  
            PRIM_ROT_LOCAL, rot,
            PRIM_SIZE, spheresize
            //PRIM_COLOR, ALL_SIDES, <1, 1, 1>, 1
            ];
    }   

    llSetLinkPrimitiveParamsFast(1, params);
}

dialog(key id)
{
    string runningstring;
    if(running)
        runningstring = "notrunning";
    else
        runningstring = "running";

    string linesstring;
    if(lines)
        linesstring = "nolines";
    else
        linesstring = "lines";
    string prompt = "\npoints: " + (string)points + "\nmultiplier: " + (string)multiplier;
    string buttons = runningstring + ",points+,points-,reset,multiplier+,multiplier-," + linesstring + ",www";
    llMessageLinked(1, 0, (string)id + "," + prompt + "," + (string)chan + "," + buttons, "");
    //llDialog(id, prompt, llCSV2List(buttons), chan);
}

default
{
    state_entry()
    {
        chan = (integer)("0x" + llGetSubString((string)llGetKey(), -8, -1));
        lh = llListen(chan, "", "", "");

        desc(FALSE);
        init();
        run();
        llSetTimerEvent(interval);
    }

    on_rez(integer param)
    {
        llListenRemove(lh);
        chan = (integer)("0x" + llGetSubString((string)llGetKey(), -8, -1));
        lh = llListen(chan, "", "", "");
    }

    touch_start(integer total_number)
    {
        key id = llDetectedKey(0);
        dialog(id);
    }

    timer()
    {
        if(!running)
            return;

        angle += rate;
        if(angle > 360)
            angle -= 360;
        else if(angle < 0)
            angle += 360;

        run();
    }

    listen(integer channel, string name, key id, string msg)
    {
        if(msg == "points+")
        {
            if(points < maxpoints)
            {
                points++;
                desc(TRUE);
                llResetScript();            
            }
        }
        else if(msg == "points-")
        {
            if(points > 0)
            {
                points--;
                desc(TRUE);
                llResetScript();
            }
        }        
        else if(msg == "multiplier+")
        {
            multiplier++;
            desc(TRUE);
        }
        else if(msg == "multiplier-")
        {
            multiplier--;
            desc(TRUE);
        }
        else if(msg == "running")
        {
            running = TRUE;
            desc(TRUE);
        }
        else if(msg == "notrunning")
        {
            running = FALSE;
            desc(TRUE);
        }
        else if(msg == "lines")
        {
            lines = TRUE;
            desc(TRUE);
            llResetScript();
        }
        else if(msg == "nolines")
        {
            lines = FALSE;
            desc(TRUE);
            llResetScript();
        }
        else if(msg == "reset")
            llResetScript();
        else if(msg == "www")
            llRegionSayTo(id, 0, url);
        dialog(id);
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.