Crea un'animazione di illusione circolare


84

Il tuo compito è quello di animare questa illusione circolare . Sembra che i punti ruotino all'interno del cerchio, ma in realtà si stanno solo muovendo in linea retta.

inserisci qui la descrizione dell'immagine

Caratteristiche

  • Il risultato deve essere animato. Il modo in cui fai l'animazione è irrilevante, può generare un .gif, può disegnare su una finestra, su uno schermo del dispositivo o altro.
  • Questo è un concorso di popolarità, quindi potresti voler aggiungere alcune funzionalità aggiuntive al tuo programma per ottenere più voti, ad esempio variando il numero di punti.
  • Il vincitore è la risposta valida più votata 7 giorni dopo l'ultimo invio valido.
  • Le risposte che implementeranno effettivamente i punti che si muovono su rette e non in un altro modo sono più apprezzate

"il vincitore è il più votato valido dopo 7 giorni". Quindi se qualcuno pubblica qualcosa ogni 6 giorni fino alla morte delle stelle, non abbiamo un vincitore?
Kevin L,

3
@KevinL che è improbabile che accada e non penso che quei 15 rappresentanti extra siano così importanti rispetto a tutti i voti che otterresti da questa domanda che viene portata in cima ogni 6 giorni.
Martin Ender,

1
A volte mi chiedo se alcune persone lo fanno solo per fare un lavoro ...
Daniel Pendergast,

3
"Sembra che i punti ruotino all'interno del cerchio, ma in realtà si stanno solo muovendo in linea retta." O, forse, stanno davvero ruotando all'interno di un cerchio e sembrano muoversi in linea retta ...
coredump,

1
Non riesco a togliermi dall'animazione questa animazione .. soprattutto la versione a 3 punti!
Thomas,

Risposte:


126

Python 3.4

Utilizzando il modulo tartaruga. Le tartarughe sono di diversi colori e si affacciano sempre nella stessa direzione, quindi si può facilmente vedere che si muovono lungo linee rette semplicemente concentrandosi su uno di essi. Nonostante ciò, l'illusione del cerchio è ancora forte.

11 tartarughe

L'illusione sembra ancora abbastanza forte anche con solo 3 o 4 tartarughe:

3 tartarughe4 tartarughe

Il framerate è notevolmente ridotto per tutti questi esempi GIF, ma non sembra sminuire l'illusione. L'esecuzione locale del codice fornisce un'animazione più fluida.

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

Per contrasto qui ce ne sono alcuni che ruotano davvero:

23 tartarughe ad anello23 tartarughe a trifoglio

... o loro?

Il codice può essere eseguito con 5 argomenti opzionali: popolazione, risoluzione, loop, vibrazione e linee.

  • population è il numero di tartarughe
  • resolution è la risoluzione temporale (numero di fotogrammi di animazione per ripetizione)
  • loopsdetermina quante volte le tartarughe tornano su se stesse. Il valore predefinito 1 indica un cerchio standard, altri numeri dispari danno quel numero di anelli nella sequenza di tartarughe, mentre i numeri pari danno una serie di tartarughe disconnesse alle estremità, ma sempre con l'illusione del movimento curvo.
  • flipse diverso da zero fa in modo che le tartarughe ribaltino la direzione per il loro viaggio di ritorno (come suggerito dall'aslum in modo che non si muovano mai all'indietro). Come impostazione predefinita, mantengono una direzione fissa per evitare la distrazione visiva agli endpoint.
  • lines se diverso da zero visualizza le linee su cui si muovono le tartarughe, per coerenza con l'immagine di esempio nella domanda.

Esempi con flipset, con e senza lines. Ho lasciato il mio esempio principale sopra senza capovolgere poiché preferisco non avere il salto sporadico, ma il bordo del cerchio sembra più liscio con tutte le tartarughe allineate, quindi l'opzione è lì per le persone a scegliere lo stile che preferiscono quando corrono il codice.

11 tartarughe con flip e righe11 tartarughe con vibrazione

Potrebbe non essere immediatamente ovvio come le immagini sopra siano state tutte prodotte da questo stesso codice. In particolare l'immagine più in alto che ha un loop esterno lento e un loop interno veloce (quello che sembra un cardioide che qualcuno ha accidentalmente lasciato cadere). Ho nascosto la spiegazione di questo qui sotto nel caso in cui qualcuno voglia ritardare di scoprirlo mentre sperimenta / pensa.

L'animazione con un loop interno ed esterno di diverse dimensioni è stata creata impostando il numero di loop su 15 e lasciando il numero di tartarughe su 23 (troppo basso per rappresentare 15 loop). L'uso di un gran numero di tartarughe comporterebbe 15 anelli chiaramente definiti. L'uso di troppe tartarughe comporta l'aliasing (per lo stesso motivo dell'elaborazione e del rendering delle immagini). Cercare di rappresentare una frequenza troppo alta comporta la visualizzazione di una frequenza più bassa, con distorsione.

Cercando numeri diversi ho trovato alcune di queste distorsioni più interessanti rispetto agli originali più simmetrici, quindi ho voluto includerne uno qui ...


18
Mi piacciono le tartarughe.
FreeAsInBeer,

18
Ho
sborsato

@ProgramFOX grazie per l'evidenziazione della sintassi! Ho cercato l'aiuto e la meta e mi sono convinto che non abbiamo avuto l'evidenziazione della sintassi sul codice golf - Sono molto più felice con questo ora.
trichoplax,

1
@aslum sarebbe un cambiamento semplice da fare, ma volevo che il loro orientamento fosse congelato per enfatizzare davvero il fatto che non si discostassero dal loro percorso in linea retta. Forse dovrei aggiungerlo al codice come opzione in modo che le persone possano scegliere l'approccio che preferiscono.
trichoplax,

4
+1 - Sarebbe fantastico vedere una banda che fa alcuni di questi più divertenti!
mkoistinen,

96

C

Risultato:

inserisci qui la descrizione dell'immagine

#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 alcuni frame è un po 'fuori. Ma complimenti per averlo fatto in ASCII!
solo il

10
+1 per ASCII esystem("cls"); // xD
Christoph Böhmwalder il

1
Questo è bellissimo.
trichoplax,

1
Questo funziona su Linux. (anche se piuttosto miseramente)
user824294

Commento obbligatorio per chi odia: "Questo non è C! Lo standard non definisce Sleep, COORD o SetConsoleCursorPosition!"
user253751,

52

SVG (no Javascript)

JSFiddle link qui

<?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, sono sicuro che questo risponda alle regole, ma sono stato, personalmente, deluso dal fatto che tu stia effettivamente facendo il contrario. Piuttosto che "Sembra che i punti [stiano ruotando all'interno del cerchio, ma in realtà si stanno solo muovendo in linea retta ". semplicemente ruotando all'interno del cerchio . ”
mkoistinen,

Risposta più fluida!
Derek 功夫 會 功夫

14
@mkoistinen Capisco cosa intendi, ma i punti si muovono davvero in linea retta. Capita solo di essere più facile calcolare le loro posizioni con due rotazioni :-)
ossifrage schizzinoso

Hai fatto tutto 'a mano' o hai usato qualsiasi tipo di editor (non testuale)?
flawr

5
@flawr Ho appena usato un semplice editor di testo e la calcolatrice nel mio telefono per calcolare i numeri :-)
ossifrage squeamish

47

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

intervaltimecambia l'FPS (FPS = 1000 / intervaltime).
ballscambia le # palline.
maxstepregola i # passi in un ciclo, maggiore è il 'liscio'. 64 dovrebbe essere abbastanza grande dove appare liscio.

Modellato come un cerchio in movimento, invece di muovere le palle lungo le linee, ma l'effetto visivo (dovrebbe essere?) Lo stesso. Parte del codice è piuttosto dettagliato, ma questo non è un codice golf, quindi ...

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
È così liscio! Molto bella.
nneonneo,

5
Non usare setInterval per le animazioni, prendi requestAnimationFrameinvece . JSFiddle modificato usando requestAnimationFrame.
klingt.net,

1
Con solo alcune modifiche ai parametri si ottiene una cosa molto diversa .
FreeAsInBeer,

@KevinL Sì, ho notato anche quello. Aggiornato.
FreeAsInBeer,

1
@FreeAsInBeer Oh, quando hai detto una cosa molto diversa, ho pensato che intendevi come quelli di jsfiddle.net/z6vhD/100
Kevin L

41

Animazioni CSS

Una soluzione che utilizza solo animazioni CSS (vedi animazione su JSFiddle - nota che ho aggiunto i prefissi specifici del browser nel violino in modo che possa funzionare nelle versioni più recenti).

<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
Fiddle non funziona per me sull'ultimo Chrome = /
mkoistinen il

1
@mkoistinen - Devi aggiungere prefissi diversi perché funzioni in diversi browser. ( -webkit-per Webkit e -moz-Mozilla) Ecco lo stesso violino con prefissi aggiornati: jsfiddle.net/nBCxz/3
Derek 朕 會 功夫

@mkoistinen Hai ragione. Il nuovo violino aggiunge tutti i prefissi del browser necessari e funziona sull'ultimo Chrome.
Howard,

Nel testo del link non elaborato manca solo la parentesi di chiusura - ancora perfettamente utilizzabile solo per farti sapere nel caso in cui volessi risolverlo (non posso, poiché cambiano meno di 6 caratteri).
trichoplax,

35

matematica

Ecco una presentazione piuttosto semplice.

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

Se chiami animateCircle[32]otterrai un'animazione ordinata con 32 linee e cerchi.

inserisci qui la descrizione dell'immagine

È completamente fluido in Mathematica, ma ho dovuto limitare un po 'il numero di fotogrammi per la GIF.

Cosa succede se metti due dischi su ogni riga? (Cioè, aggiungi Disk[-Sin[t + phase]*line, 0.05]all'elenco all'interno di Map.)

inserisci qui la descrizione dell'immagine

Puoi anche metterli sfasati di 90 ° (usa Cosinvece di -Sin):

inserisci qui la descrizione dell'immagine


Non so che cosa significhi glitch, probabilmente devi cambiare {t, 0, 2 \[Pi]}in {t, 0, 2 \[Pi] - 2 \[Pi]/60, 2 \[Pi]/60}modo che non ci siano due frame identici e cambiare Animatein Table. Quindi sarai in grado di esportare GIF.
Swish,

@swish No, in realtà rende strane righe aggiuntive che non ci sono e i dischi in luoghi dove non dovrebbero essere (e dove non sono mai nel risultato reale di Animate). Proverò a usarlo di Tablenuovo però.
Martin Ender,

@swish Ha funzionato. Pensavo di aver provato qualcosa del genere ieri, ma a quanto pare non l'ho fatto.
Martin Ender,

25

Grafico a torta VBScript + VBA + Excel

Questo farà piangere un po 'il tuo processore, ma sembra carino e credo che funzioni secondo le specifiche. Ho usato la risposta di @ Fabricio come guida per implementare l'algoritmo di movimento del cerchio.

EDIT: apportate alcune modifiche per migliorare la velocità di rendering.

Schermata del grafico a torta

Il codice:

'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

Si blocca per me alla riga 81, errore 80070057, "l'elemento con il nome specificato non esiste" o qualcosa del genere (tradotto dall'ungherese, ecco perché non conosco l'esatto messaggio di errore).
marczellm,

Szervusz, @marczellm. Posso riprodurre quell'errore quando faccio clic al di fuori del grafico mentre è "animando". Devi consentire la messa a fuoco o il programma si guasterà. In caso contrario, ciò potrebbe essere dovuto a un'incompatibilità con Office. Sono su Office 2010 su Win7.
comodamente

Office 2007, Win7. Sembra che nel mio caso il grafico non si concentri affatto.
marczellm,

21

Excel, 161 byte

Eccellere

=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 (punto) determina il tempo (secondi) per una 'rivoluzione' completa.

Ogni cella all'interno delle linee è una condizione di base relativa al valore della linea corrispondente. Ad esempio, K2 è:

 =1*(A5=7)

E la cella centrale (K9) è:

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

Hai forzato l'animazione tenendo premuto 'Elimina' su una cella casuale per attivare costantemente un aggiornamento.

So che questo è un vecchio argomento, ma l'attività recente lo ha portato in cima e per qualche motivo sembrava attraente. Ascoltatore pcg da molto tempo, chiamante per la prima volta. Sii gentile.


Wow, è incredibile che tu possa farlo con Excel: D
Beta Decay

15

Solo per divertimento con PSTricks.

inserisci qui la descrizione dell'immagine

\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

Ogni fotogramma viene creato come un singolo file gif usando il modulo gif di Fortran su: http://fortranwiki.org/fortran/show/writegif
Quindi imbroglio un po 'usando ImageMagick per unire le singole gif in una gif animata.

Fortran

AGGIORNAMENTO: imposta new = .true. per ottenere quanto segue:

inserisci qui la descrizione dell'immagine

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
Mi piace l'impatto "squish" per gli elementi verticali e orizzontali.
Portland Runner,

11

Versione C64 obbligatoria .

Copia e incolla nel tuo emulatore preferito:

Versione 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

Una versione javascript compatta, che modifica le impostazioni predefinite in qualcosa di diverso

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
Hai fatto ... una ciambella ?? In realtà la tua animazione sembra bella con punti più piccoli (prova bw=10). Modifica la tua risposta per mostrare il tuo codice. Oh, e mentre ci sei, c'è un bug che dovresti correggere: sostituiscilo time+i*0.39*0.29con time+i*Math.PI/numi calcoli del trigro in modo che le coordinate siano calcolate correttamente per qualsiasi valore di num. (PS aggiornato JSFiddle qui . E benvenuto su codegolf.stackexchange.com)
ossifrage schizzinoso

Volevo solo fare qualcosa di diverso (come quello delle tartarughe). Newbie here in codegolf :) Oh, e grazie per la formula: DI l'ho appena fatto in fretta e ha provato valori casuali, non si è fermato un minuto per arrivare alla formula corretta: P
Diego

1
+1 Piccolo cambiamento per un po 'di divertimento visivo: http://jsfiddle.net/9TQrm/ o http://jsfiddle.net/Wrqs4/1/
Portland Runner

4

La mia opinione su Elm . Sono un principiante assoluto che accetterà felicemente le PR per migliorare questa soluzione ( GitHub ):

inserisci qui la descrizione dell'immagine

Nota che questa presentazione sta davvero spostando i punti su rette:

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
Quel cursore mi ha ingannato bene e il mio non è nemmeno nero o di quelle dimensioni.
Cole,

2

Second Life LSL

animazione inizio dell'immagine alfa della tartaruga (fare clic con il tasto destro in basso per salvare l'immagine)
turtle.png
fine dell'immagine alfa della tartaruga (fare clic con il tasto destro in alto per salvare l'immagine)

costruire l'oggetto:
creare una dimensione del cilindro prim radice <1, 1, 0,01> fetta 0,49, 0,51, colore < 0, 0, 0>
rendere la descrizione di questo cilindro "8,1,1,1" senza virgolette (molto importante)
creare un cilindro, denominarlo "cil", colore <0,25, 0,25, 0,25> alfa 0,5
duplicare il cil 48 volte
crea una scatola, chiamala "sfera", colore <1, 1, 1> trasparenza 100 tranne per la trasparenza superiore 0
metti la tua trama di tartaruga sulla faccia 0 della scatola, la tartaruga dovrebbe essere rivolta + x
duplica la scatola 48 volte
seleziona tutte le scatole e i cilindri, assicurati di selezionare l'ultimo cilindro principale,collegamento (controllo L)

metti questi 2 script nella radice:

//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);
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.