Machen Sie eine Kreisillusionsanimation


84

Ihre Aufgabe ist es, diese zu animieren Kreis Illusion . Es sieht so aus, als würden sich die Punkte innerhalb des Kreises drehen, aber sie bewegen sich tatsächlich nur in geraden Linien.

Bildbeschreibung hier eingeben

Kriterien

  • Das Ergebnis muss animiert werden. Die Art und Weise, wie Sie die Animation ausführen, ist irrelevant. Sie kann eine erzeugen .gif, in ein Fenster zeichnen, einen Gerätebildschirm oder was auch immer.
  • Dies ist ein Beliebtheitswettbewerb, daher möchten Sie Ihrem Programm möglicherweise einige zusätzliche Funktionen hinzufügen, um mehr Upvotes zu erhalten, z. B. die Anzahl der Punkte zu variieren.
  • Der Gewinner ist die am besten bewertete gültige Antwort 7 Tage nach der letzten gültigen Einreichung.
  • Die Antworten, bei denen Punkte auf geraden Linien und nicht anders herum umgesetzt werden, sind willkommener

"Der Gewinner ist der am häufigsten gewählte, der nach 7 Tagen gültig ist". Wenn also alle 6 Tage jemand etwas veröffentlicht, bis die Sterne sterben, haben wir keinen Gewinner?
Kevin L

3
@ KevinL das ist unwahrscheinlich und ich denke nicht, dass diese 15 zusätzlichen Wiederholungen so wichtig sind im Vergleich zu all den positiven Stimmen, die man von dieser Frage bekommt, wenn man alle 6 Tage nach oben stößt.
Martin Ender

1
Manchmal frage ich mich, ob manche Leute das nur tun, um einen Job zu erledigen ...
Daniel Pendergast

3
"Es sieht so aus, als ob sich die Punkte innerhalb des Kreises drehen, aber sie bewegen sich tatsächlich nur in geraden Linien." Oder, vielleicht drehen sie sich wirklich innerhalb eines Kreises und scheinen sich in geraden Linien zu bewegen ...
coredump

1
Ich kann diese Animation nicht verstehen, besonders nicht die 3-Punkte-Version!
Thomas

Antworten:


126

Python 3.4

Verwendung des Turtle-Moduls. Die Schildkröten haben unterschiedliche Farben und sind immer in die gleiche Richtung ausgerichtet. Sie können also leicht erkennen, dass sie sich entlang gerader Linien bewegen, indem Sie sich nur auf eine von ihnen konzentrieren. Trotzdem ist die Kreisillusion immer noch stark.

11 Schildkröten

Die Illusion scheint auch mit nur 3 oder 4 Schildkröten noch ziemlich stark zu sein:

3 Schildkröten4 Schildkröten

Die Framerate wird für alle diese GIF-Beispiele erheblich reduziert, scheint aber die Illusion nicht zu beeinträchtigen. Das lokale Ausführen des Codes sorgt für eine flüssigere Animation.

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:]))

Im Gegensatz dazu sind hier einige, die sich wirklich drehen:

23 Schleifenschildkröten23 Kleeschildkröten

... oder doch?

Der Code kann mit 5 optionalen Argumenten ausgeführt werden: Auffüllung, Auflösung, Schleifen, Flip und Linien.

  • population ist die Anzahl der Schildkröten
  • resolution ist die zeitliche Auflösung (Anzahl der Animationsbilder pro Wiederholung)
  • loopslegt fest, wie oft die Schildkröten auf sich selbst zurückkehren. Der Standardwert 1 gibt einen Standardkreis an, andere ungerade Zahlen geben die Anzahl der Schleifen in der Schildkrötenkette an, während gerade Zahlen eine Kette von Schildkröten ergeben, die an den Enden getrennt sind, aber immer noch die Illusion einer gekrümmten Bewegung zeigen.
  • flipWenn der Wert nicht Null ist, kehren die Schildkröten für ihre Rückfahrt um (wie von aslum vorgeschlagen, damit sie sich niemals rückwärts bewegen). Standardmäßig behalten sie eine feste Richtung bei, um die visuelle Ablenkung an den Endpunkten zu vermeiden.
  • lines Wenn nicht Null, werden die Linien angezeigt, auf denen sich die Schildkröten bewegen, um die Übereinstimmung mit dem Beispielbild in der Frage zu gewährleisten.

Beispiele mit flipSatz, mit und ohne lines. Ich habe mein Hauptbeispiel oben ohne Flip gelassen, da ich es vorziehen würde, nicht sporadisch zu springen, aber der Rand des Kreises sieht bei allen ausgerichteten Schildkröten gleichmäßiger aus, sodass die Leute wählen können, welchen Stil sie beim Laufen bevorzugen der Code.

11 Schildkröten mit Flip und Linien11 Schildkröten mit Flip

Es ist möglicherweise nicht sofort ersichtlich, wie die obigen Bilder alle mit demselben Code erstellt wurden. Insbesondere das Bild weiter oben, das eine langsame äußere und eine schnelle innere Schleife aufweist (die wie eine Niere aussieht, die jemand versehentlich fallen gelassen hat). Ich habe die Erklärung dieser unten versteckt, falls jemand das später herausfinden möchte, während er experimentiert / nachdenkt.

Die Animation mit einer inneren und einer äußeren Schleife unterschiedlicher Größe wurde erstellt, indem die Anzahl der Schleifen auf 15 festgelegt und die Anzahl der Schildkröten auf 23 belassen wurde (zu niedrig, um 15 Schleifen darzustellen). Die Verwendung einer großen Anzahl von Schildkröten würde zu 15 klar definierten Schleifen führen. Die Verwendung zu weniger Schildkröten führt zu einem Aliasing (aus dem gleichen Grund wie bei der Bildverarbeitung und -wiedergabe). Der Versuch, eine zu hohe Frequenz darzustellen, führt dazu, dass eine niedrigere Frequenz mit Verzerrung angezeigt wird.

Als ich verschiedene Zahlen ausprobierte, fand ich einige dieser Verzerrungen interessanter als die symmetrischeren Originale, deshalb wollte ich hier eine einfügen ...


18
Ich mag Schildkröten.
FreeAsInBeer

18
Ich habe +1 für die Schildkröten
ausgesondert

@ProgramFOX danke für die Syntax-Hervorhebung! Ich habe die Hilfe und das Meta durchsucht und mich davon überzeugt, dass es keine Syntaxhervorhebung für Codegolf gibt - damit bin ich jetzt viel zufriedener.
Trichoplax

1
@aslum das wäre eine unkomplizierte änderung, aber ich wollte, dass ihre ausrichtung wirklich eingefroren wird, um zu betonen, dass sie nicht von ihrem geradlinigen verlauf abweichen. Vielleicht sollte ich es dem Code als Option hinzufügen, damit die Leute den Ansatz wählen können, den sie bevorzugen.
Trichoplax

4
+1 - Es wäre großartig zu sehen, wie eine Blaskapelle einige dieser funkigeren Bands spielt!
mkoistinen

96

C

Ergebnis:

Bildbeschreibung hier eingeben

#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
In einigen Frames ist es ein bisschen aus. Aber herzlichen Glückwunsch dazu in ASCII!
Nur die Hälfte des

10
+1 für ASCII undsystem("cls"); // xD
Christoph Böhmwalder

1
Das ist schön.
Trichoplax


Obligatorischer Hasser-Kommentar: "Dies ist nicht C! Der Standard definiert nicht Sleep, COORD oder SetConsoleCursorPosition!"
user253751

52

SVG (kein Javascript)

JSFiddle Link hier

<?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>

Hmmm, ich bin sicher, dass dies den Regeln entspricht, aber ich persönlich war enttäuscht, dass Sie tatsächlich das Gegenteil tun. Anstatt "Es sieht so aus, als ob sich die Punkte innerhalb des Kreises drehen, aber sie bewegen sich tatsächlich nur in geraden Linien ." nur innerhalb des Kreises drehen . ”
mkoistinen

Reibungsloseste Antwort!
Derek 朕 朕 功夫

14
@mkoistinen Ich verstehe, was du meinst, aber die Punkte bewegen sich wirklich in geraden Linien. Es passiert einfach leichter sein , um ihre Positionen mit zwei Umdrehungen zu berechnen :-)
zimperlich ossifrage

Haben Sie alles von Hand gemacht oder haben Sie einen (Nicht-Text-) Editor verwendet?
Fehler

5
@flawr Ich habe gerade einen einfachen Texteditor und den Taschenrechner in meinem Telefon verwendet, um die Zahlen zu berechnen :-)
zimperlicher Ossifrage

47

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

intervaltimeändert die FPS (FPS = 1000 / Intervallzeit).
ballsändert die # Bälle.
maxstepPasst die # -Schritte in einem Zyklus an, je größer die Glättung ist. 64 sollte groß genug sein, wo es glatt erscheint.

Modelliert als Kreis, der sich bewegt, anstatt die Kugeln entlang der Linien zu bewegen, aber der visuelle Effekt sollte der gleiche sein. Ein Teil des Codes ist ziemlich ausführlich, aber das ist kein Code-Golf, also ...

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
Es ist so glatt! Sehr schön.
Nneonneo

5
Verwenden Sie setInterval nicht für Animationen, requestAnimationFramesondern nehmen Sie stattdessen . Modifizierte JSFiddle mit requestAnimationFrame.
klingt.net

1
Mit nur wenigen Parameteränderungen erhalten Sie eine ganz andere Sache .
FreeAsInBeer

@ KevinL Yep, gerade bemerkt, dass auch. Aktualisiert.
FreeAsInBeer

1
@FreeAsInBeer Oh, als Sie etwas ganz anderes sagten, dachte ich, Sie meinen es so wie in jsfiddle.net/z6vhD/100
Kevin L

41

CSS-Animationen

Eine Lösung, die nur CSS-Animationen verwendet (siehe Animation in JSFiddle - Beachten Sie, dass ich die browserspezifischen Präfixe in die Geige eingefügt habe, damit sie in den neuesten Versionen funktionieren können).

<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
Geige funktioniert nicht für mich auf neuesten Chrome = /
mkoistinen

1
@mkoistinen - Sie müssen verschiedene Präfixe hinzufügen, damit es in verschiedenen Browsern funktioniert. ( -webkit-für Webkit-basierte und -moz-für Mozilla-basierte) Hier ist die gleiche Geige mit aktualisierten Präfixen: jsfiddle.net/nBCxz/3
Derek 朕 會 功夫

@ mkoistinen Du hast recht. Die neue Geige fügt alle erforderlichen Browser-Präfixe hinzu und funktioniert mit dem neuesten Chrome.
Howard

Dem rohen Linktext fehlt nur die schließende Klammer - er ist immer noch perfekt verwendbar und lässt Sie wissen, falls Sie ihn korrigieren möchten (ich kann es nicht, da weniger als 6 Zeichen geändert werden müssen).
Trichoplax

35

Mathematica

Hier ist eine ziemlich direkte Einreichung.

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]}
  ]

Wenn Sie anrufen, erhalten animateCircle[32]Sie eine übersichtliche Animation mit 32 Linien und Kreisen.

Bildbeschreibung hier eingeben

In Mathematica ist das völlig reibungslos, aber ich musste die Anzahl der Frames für das GIF etwas begrenzen.

Was passiert nun, wenn Sie zwei Discs in jede Zeile einlegen? (Das heißt, Disk[-Sin[t + phase]*line, 0.05]zur Liste in der Liste hinzufügen Map.)

Bildbeschreibung hier eingeben

Sie können sie auch um 90 ° phasenverschoben ( Cosstatt verwenden -Sin):

Bildbeschreibung hier eingeben


Ich weiß nicht , welche Pannen meinen Sie, wahrscheinlich müssen Sie ändern , {t, 0, 2 \[Pi]}um {t, 0, 2 \[Pi] - 2 \[Pi]/60, 2 \[Pi]/60}so , dass es nicht zwei identische Rahmen und ändern Animatezu Table. Dann können Sie GIF exportieren.
Swish

@swish Nein, es rendert tatsächlich seltsame zusätzliche Zeilen, die nicht vorhanden sind, und die Discs an Stellen, an denen sie nicht vorhanden sein sollten (und an denen sie sich nie im tatsächlichen Ergebnis von befinden Animate). Ich werde es aber noch Tableeinmal versuchen .
Martin Ender

@swish Das hat funktioniert. Ich dachte, ich hätte gestern so etwas versucht, aber anscheinend nicht.
Martin Ender

25

VBScript + VBA + Excel-Kreisdiagramm

Dadurch wird Ihr Prozessor ein wenig weinen, aber es sieht hübsch aus und ich glaube, es funktioniert nach Spezifikation. Ich habe die Antwort von @ Fabricio als Leitfaden für die Implementierung des Kreisbewegungsalgorithmus verwendet.

BEARBEITEN: Einige Anpassungen vorgenommen, um die Rendergeschwindigkeit zu verbessern.

Bildschirmfoto von Tortendiagramm

Der Code:

'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

Es stürzt für mich in Zeile 81 ab, Fehler 80070057, "Element mit dem angegebenen Namen existiert nicht" oder so ähnlich (aus dem Ungarischen übersetzt, deshalb kenne ich die genaue Fehlermeldung nicht).
Marczellm

Szervusz, @marczellm. Ich kann diesen Fehler reproduzieren, wenn ich außerhalb des Diagramms klicke, während es "animiert" wird. Sie müssen das Fokussieren zulassen, da sonst das Programm einen Fehler verursacht. Andernfalls liegt möglicherweise eine Inkompatibilität mit Office vor. Ich bin in Office 2010 auf Win7.
comfortablydrei

Office 2007, Win7. Scheint, als würde das Diagramm in meinem Fall überhaupt nicht fokussiert.
Marczellm

21

Excel 161 Byte

Excel

=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 (Punkt) bestimmt die Zeit (Sekunden) für eine volle "Umdrehung".

Jede Zelle innerhalb der Zeilen ist eine Grundbedingung in Bezug auf den Wert der entsprechenden Zeile. Zum Beispiel ist K2:

 =1*(A5=7)

Und die mittlere Zelle (K9) ist:

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

Erzwingt die Animation, indem 'delete' in einer zufälligen Zelle gedrückt gehalten wird, um ständig eine Aktualisierung auszulösen.

Ich weiß, dass dies ein altes Thema ist, aber die jüngsten Aktivitäten haben es an die Spitze gebracht und es schien aus irgendeinem Grund ansprechend. Langzeit-PCG-Listener, erster Anrufer. Sei sanft.


Wow, das ist unglaublich, dass man das mit Excel machen kann: D
Beta Decay

15

Nur zum Spaß mit PSTricks.

Bildbeschreibung hier eingeben

\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

Jeder Frame wird mithilfe des Fortran-Gif-Moduls als individuelle Gif-Datei erstellt: http://fortranwiki.org/fortran/show/writegif.
Dann betrüge ich ein wenig mit ImageMagick, um die einzelnen Gifs zu einem animierten Gif zusammenzuführen.

Fortran

UPDATE: Setze new = .true. um folgendes zu bekommen:

Bildbeschreibung hier eingeben

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
Ich mag den Aufprall "Quetschen" für die vertikalen und horizontalen Elemente.
Portland Runner

11

Verpflichtend C64- Version.

Kopieren und Einfügen in Ihren Lieblingsemulator:

C64-Version

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

Eine kompakte Javascript-Version, bei der die Standardeinstellungen auf etwas anderes geändert werden

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
Du hast ... einen Donut gemacht ? Tatsächlich sieht Ihre Animation mit kleineren Punkten (Versuch bw=10) nett aus . Bitte bearbeiten Sie Ihre Antwort, um Ihren Code anzuzeigen. Oh, und während Sie gerade dabei sind, gibt es einen Fehler , den Sie sollten beheben: ersetzen time+i*0.39*0.29mit time+i*Math.PI/numin den trigonometrischen Berechnungen , so dass die Koordinaten richtig für jeden Wert von berechnet werden num. (PS Aktualisiert JSFiddle hier Und willkommen in codegolf.stackexchange.com.)
zimperlich ossifrage

Ich wollte nur etwas anderes machen (wie die Schildkröten). Anfänger hier in Codegolf :) Oh, und danke für die Formel: DI hat es nur eilig gemacht und versucht, Zufallswerte zu ermitteln, hat keine Minute aufgehört, um zur richtigen Formel zu gelangen: P
Diego

1
+1 Kleine Änderung für ein wenig visuellen Spaß: http://jsfiddle.net/9TQrm/ oder http://jsfiddle.net/Wrqs4/1/
Portland Runner

4

Meine Einstellung zu Elm . Ich bin ein absoluter Anfänger, der gerne PRs akzeptiert, um diese Lösung zu verbessern ( GitHub ):

Bildbeschreibung hier eingeben

Beachten Sie, dass diese Übermittlung wirklich Punkte auf geraden Linien verschiebt:

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
Dieser Cursor hat mich gut getäuscht, und meiner ist nicht einmal schwarz oder so groß.
Cole

2

Second Life LSL

Animation Beginn des Schildkröten-Alpha-Bildes (Rechtsklick zum Speichern des Bildes)
turtle.png
Ende des Schildkröten-Alpha-Bildes (Rechtsklick zum Speichern des Bildes)

Erstellen des Objekts:
Erstellen Sie einen Root-Prim-Zylinder der Größe <1, 1, 0,01> in 0,49, 0,51, Farbe < 0, 0, 0>
machen die Beschreibung dieses Zylinders "8,1,1,1" ohne die Anführungszeichen (sehr wichtig)
machen einen Zylinder, nennen es "Zyl", Farbe <0,25, 0,25, 0,25> Alpha 0,5
duplizieren die Mache 48 Mal
eine Schachtel, nenne sie "Kugel", färbe <1, 1, 1> Transparenz 100 mit Ausnahme der oberen Transparenz 0
Lege deine Schildkrötentextur auf Gesicht 0 der Schachtel, Schildkröte sollte Gesicht + x sein und
die Schachtel 48 Mal duplizieren
wähle alle Kästchen und Zylinder aus, stelle sicher, dass der Wurzelzylinder zuletzt ausgewählt ist,Verbindung (Kontrolle L)

Setze diese 2 Skripte in den Root:

//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);
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.