Faire une animation de cercle illusion


84

Votre travail consiste à animer cette illusion de cercle . On dirait que les points tournent à l’intérieur du cercle, mais ils ne font que se déplacer en ligne droite.

entrez la description de l'image ici

Critères

  • Le résultat doit être animé. La manière dont vous faites l’animation n’a aucune importance, elle peut générer une .gif, elle peut s’afficher dans une fenêtre, un écran de périphérique ou autre.
  • Il s’agit d’un concours de popularité. Vous voudrez peut-être ajouter des fonctionnalités supplémentaires à votre programme pour obtenir davantage de votes positifs, par exemple en modifiant le nombre de points.
  • Le gagnant est la réponse valide la plus votée 7 jours après la dernière soumission valide.
  • Les réponses qui impliqueront réellement des points se déplaçant sur des lignes droites et non un autre moyen sont plus appréciées

"le gagnant est le plus voté valide après 7 jours". Donc, si quelqu'un poste quelque chose tous les 6 jours jusqu'à la mort des étoiles, nous n'avons pas de gagnant?
Kevin L

3
@KevinL, il est peu probable que cela se produise et je ne pense pas que ces 15 représentants supplémentaires soient si importants par rapport à tous les votes positifs que vous obtiendriez de cette question repoussant tous les six jours au sommet.
Martin Ender

1
Parfois, je me demande si certaines personnes le font simplement pour avoir du travail ...
Daniel Pendergast

3
« Il semble que les points de rotation à l' intérieur du cercle, mais ils sont en fait juste déplacer dans les lignes droites. », Ou, peut - être qu'ils tournent vraiment à l' intérieur d' un cercle et semblent se déplacer en ligne droite ...
coredump

1
Je ne peux pas .. obtenir cette animation .. de mon esprit .. surtout la version à 3 points!
Thomas

Réponses:


126

Python 3.4

Utilisation du module tortue. Les tortues sont de couleurs différentes et elles font toujours face dans la même direction, de sorte qu'on peut facilement les voir se déplacer le long de lignes droites en se concentrant simplement sur l'une d'entre elles. Malgré cela, l'illusion du cercle est toujours forte.

11 tortues

L'illusion semble encore assez forte même avec seulement 3 ou 4 tortues:

3 tortues4 tortues

Le nombre d'images par seconde est considérablement réduit pour tous ces exemples de fichiers GIF, mais cela ne semble pas nous permettre de nuire à l'illusion. L'exécution du code localement donne une animation plus fluide.

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

Pour le contraste, voici quelques uns qui tournent réellement:

23 tortues en boucle23 tortues trèfles

... ou le font-ils?

Le code peut être exécuté avec 5 arguments optionnels: population, résolution, boucles, retournement et lignes.

  • population est le nombre de tortues
  • resolution est la résolution temporelle (nombre d'images d'animation par répétition)
  • loopsdétermine combien de fois les tortues reviennent sur elles-mêmes. La valeur par défaut 1 donne un cercle standard, les autres nombres impairs donnent ce nombre de boucles dans la chaîne de tortues, tandis que les nombres pairs donnent une chaîne de tortues déconnectée aux extrémités, mais avec toujours l'illusion d'un mouvement courbe.
  • flipsi non-zéro, les tortues changent de direction pour leur voyage de retour (comme suggéré par aslum pour ne jamais reculer). Par défaut, ils conservent une direction fixe pour éviter la distraction visuelle au niveau des points d'extrémité.
  • lines si non-zéro affiche les lignes sur lesquelles les tortues se déplacent, par souci de cohérence avec l'exemple d'image de la question.

Exemples avec flipensemble, avec et sans lines. J'ai laissé mon exemple principal ci-dessus sans basculement car je préfère ne pas avoir le saut sporadique, mais le bord du cercle est plus lisse avec l'alignement de toutes les tortues. Il est donc possible de choisir le style de son choix lors de la course. le code.

11 tortues avec flip et des lignes11 tortues avec flip

Il n’est peut-être pas immédiatement évident de voir comment les images ci-dessus ont toutes été produites à partir de ce même code. En particulier, l'image la plus haute qui a une boucle externe lente et une boucle interne rapide (celle qui ressemble à un cardioïde qu'une personne est tombée accidentellement). J'ai caché l'explication de celle-ci ci-dessous au cas où quelqu'un voudrait retarder sa découverte en expérimentant / réfléchissant.

L'animation avec une boucle interne et externe de différentes tailles a été créée en définissant le nombre de boucles à 15 et en laissant le nombre de tortues à 23 (trop faible pour représenter 15 boucles). L'utilisation d'un grand nombre de tortues donnerait 15 boucles clairement définies. L'utilisation d'un nombre insuffisant de tortues entraîne un aliasing (pour les mêmes raisons que pour le traitement et le rendu des images). Si vous essayez de représenter une fréquence trop élevée, une fréquence plus basse est affichée, avec distorsion.

En essayant différents nombres, j'ai trouvé certaines de ces distorsions plus intéressantes que les originales plus symétriques, alors je voulais en inclure un ici ...


18
J'aime les tortues.
FreeAsInBeer

18
J'ai bombardé +1 pour les tortues
MrEngineer13

@ProgramFOX merci pour la coloration syntaxique! J'ai cherché aide et méta et je me suis convaincu que la syntaxe ne mettait pas en évidence le code de golf - je suis beaucoup plus heureux avec cela maintenant.
Trichoplax

1
@aslum, ce serait un changement simple à faire, mais je voulais que leur orientation soit figée pour vraiment souligner qu'ils ne dévient pas de leur trajectoire en ligne droite. Je devrais peut-être ajouter cette option au code pour que les gens puissent choisir l'approche qu'ils préfèrent.
Trichoplax

4
+1 - Ce serait génial de voir une fanfare faire quelques-unes de ces plus funky!
mkoistinen

96

C

Résultat:

entrez la description de l'image ici

#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
Dans certains cadres, c'est un peu off. Mais bravo pour le faire en ASCII!
moitié

10
+1 pour ASCII etsystem("cls"); // xD
Christoph Böhmwalder

1
C'est beau.
Trichoplax

1
Celui-ci fonctionne sur linux. (bien que misérablement)
user824294

Commentaire de haine obligatoire: "Ce n'est pas C! La norme ne définit pas Sleep, COORD ou SetConsoleCursorPosition!"
user253751

52

SVG (pas de Javascript)

Lien JSFiddle ici

<?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, je suis sûr que cela va à l’encontre des règles, mais j’étais personnellement déçu que vous fassiez le contraire. Plutôt que "Il semble que les points tournent à l'intérieur du cercle, mais ils ne se déplacent que dans des lignes droites ." il suffit de tourner à l'intérieur du cercle . ”
mardi

Réponse la plus lisse!
Derek mardi

14
@mkoistinen Je vois ce que vous voulez dire, mais les points bougent vraiment en lignes droites. Il se trouve qu'il est plus facile de calculer leurs positions avec deux rotations :-)
ossifrage

Avez-vous tout fait «à la main» ou avez-vous utilisé un type quelconque d'éditeur (non textuel)?
flawr

5
@flawr Je viens d'utiliser un éditeur de texte en clair et la calculatrice de mon téléphone pour calculer les chiffres :-)
ossifrage

47

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

intervaltimechange le FPS (FPS = 1000 / intervaltime).
ballschange le nombre de balles.
maxstepajuste le nombre d'étapes dans un cycle, plus le «lissage» est grand. 64 devrait être assez grand où il semble lisse.

Modélisé comme un cercle en mouvement, au lieu de déplacer les balles le long des lignes, mais l'effet visuel (devrait être?) Identique. Une partie du code est assez verbeuse, mais ce n'est pas du code golf, alors ...

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
C'est tellement lisse! Très agréable.
nneonneo

5
N'utilisez pas setInterval pour les animations, prenez requestAnimationFrameplutôt . JSFiddle modifié en utilisant requestAnimationFrame.
klingt.net

1
Avec seulement quelques réglages de paramètres, vous obtenez une chose très différente .
FreeAsInBeer

@ Kevin_ Oui, je viens de le remarquer aussi. Mis à jour.
FreeAsInBeer

1
@FreeAsInBeer Oh, quand vous avez dit quelque chose de très différent, je pensais que vous vouliez dire comme ceux de jsfiddle.net/z6vhD/100
Kevin L

41

Animations CSS

Une solution utilisant uniquement des animations css (voir l'animation sur JSFiddle - notez que j'ai ajouté les préfixes spécifiques au navigateur dans le violon pour qu'il puisse fonctionner dans les versions les plus récentes).

<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 ne fonctionne pas pour moi sur le dernier Chrome = /
mkoistinen

1
@mkoistinen - Vous devez ajouter différents préfixes pour que cela fonctionne dans différents navigateurs. ( -webkit-pour Webkit et -moz-pour Mozilla) Voici le même violon avec les préfixes mis à jour: jsfiddle.net/nBCxz/3
Derek 會 功夫

@mkoistinen Vous avez raison. Le nouveau violon ajoute tous les préfixes de navigateur nécessaires et fonctionne sur la dernière version de Chrome.
Howard

Il manque simplement la parenthèse fermante dans le texte brut du lien - il est parfaitement utilisable, mais vous permet de le savoir au cas où vous souhaiteriez le réparer (je ne peux pas, car il faut moins de 6 caractères pour changer).
Trichoplax

35

Mathematica

Voici une soumission assez simple.

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

Si vous appelez, animateCircle[32]vous obtiendrez une animation soignée avec 32 lignes et cercles.

entrez la description de l'image ici

C’est tout à fait lisse dans Mathematica, mais j’ai dû limiter un peu le nombre d’images pour le GIF.

Maintenant que se passe-t-il si vous mettez deux disques sur chaque ligne? (C'est-à-dire, ajouter Disk[-Sin[t + phase]*line, 0.05]à la liste dans le Map.)

entrez la description de l'image ici

Vous pouvez également les mettre hors phase à 90 ° (utiliser Cosau lieu de -Sin):

entrez la description de l'image ici


Je ne sais pas ce que vous voulez dire par problèmes, probablement vous devez changer {t, 0, 2 \[Pi]}pour {t, 0, 2 \[Pi] - 2 \[Pi]/60, 2 \[Pi]/60}qu'il n'y ait pas deux images identiques et changer Animatepour Table. Ensuite, vous pourrez exporter le GIF.
Swish

@swish Non, cela crée en fait des lignes supplémentaires étranges qui n'existent pas et les disques situés dans des endroits où ils ne devraient pas se trouver (et où ils ne figurent jamais dans le résultat réel Animate). Je vais essayer d'utiliser à Tablenouveau si.
Martin Ender

@swish Cela a fonctionné. Je pensais avoir essayé quelque chose comme ça hier, mais apparemment je ne l'ai pas fait.
Martin Ender

25

Graphique à secteurs VBScript + VBA + Excel

Cela fera un peu pleurer votre processeur, mais il est joli et je pense que cela fonctionne conformément aux spécifications. J'ai utilisé la réponse de @ Fabricio comme guide pour implémenter l'algorithme de mouvement de cercle.

EDIT: fait quelques ajustements pour améliorer la vitesse de rendu.

Capture de camembert

Le 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

Il se bloque pour moi à la ligne 81, erreur 80070057, "L'élément avec le prénom n'existe pas" ou quelque chose comme ceci (traduit du hongrois, c'est pourquoi je ne connais pas le message d'erreur exact).
Marczellm

Szervusz, @marczellm. Je peux reproduire cette erreur lorsque je clique en dehors du graphique alors qu'il "anime". Vous devez autoriser la mise au point ou le programme fera une erreur. Sinon, cela peut être dû à une incompatibilité avec Office. Je suis sur Office 2010 sur Win7.
comfortablydrei

Office 2007, Win7. On dirait que dans mon cas, le graphique ne se concentre pas du tout.
Marczellm

21

Excel, 161 octets

Exceller

=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 (période) détermine le temps (secondes) pour un «tour» complet.

Chaque cellule dans les lignes est une condition de base relative à la valeur de la ligne correspondante. Par exemple, K2 est:

 =1*(A5=7)

Et la cellule centrale (K9) est:

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

Forcé l’animation en maintenant «delete» sur une cellule aléatoire pour déclencher une actualisation constante.

Je sais que c'est un sujet ancien, mais une activité récente l'a amené au sommet et cela semblait attrayant pour une raison quelconque. Listener pcg long time, premier appelant. Sois gentil.


Wow, c'est incroyable que vous puissiez le faire avec Excel: D
Beta Decay

15

Juste pour s'amuser avec PSTricks.

entrez la description de l'image ici

\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

Chaque image est créée en tant que fichier GIF individuel à l'aide du module Fortran GIF à l' adresse suivante : http://fortranwiki.org/fortran/show/writegif.
Ensuite, je triche un peu en utilisant ImageMagick pour fusionner les gifs individuels en un gif animé.

Fortran

UPDATE: Définissez new = .true. pour obtenir ce qui suit:

entrez la description de l'image ici

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
J'aime l'impact 'squish' pour les éléments verticaux et horizontaux.
Portland Runner

11

Version C64 obligatoire .

Copiez et collez dans votre émulateur préféré:

Version 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

Une version javascript compacte, changeant les paramètres par défaut pour quelque chose de différent

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
Tu as fait ... un beignet ?? En fait, votre animation a l'air bien avec des points plus petits (essayez bw=10). Veuillez modifier votre réponse pour afficher votre code. Oh, et tant que vous y êtes, il y a un bug que vous devriez corriger: remplacez time+i*0.39*0.29par time+i*Math.PI/numdans les calculs trigonométriques afin que les coordonnées soient calculées correctement pour toute valeur de num. (PS Mis à jour JSFiddle ici . Et bienvenue à codegolf.stackexchange.com)
ossifrage

Je voulais juste faire quelque chose de différent (comme celui des tortues). Débutant ici à codegolf :) Oh, et merci pour la formule: D, je l'ai fait rapidement et j'ai essayé des valeurs aléatoires, je ne me suis pas arrêté pour obtenir la bonne formule: P
Diego,

1
+1 Petit changement pour un peu de plaisir visuel: http://jsfiddle.net/9TQrm/ ou http://jsfiddle.net/Wrqs4/1/
Portland Runner

4

Ma prise avec Elm . Je suis un débutant et j'accepterai volontiers les RP pour améliorer cette solution ( GitHub ):

entrez la description de l'image ici

Notez que cette soumission déplace vraiment des points sur des lignes droites:

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
Ce curseur m'a bien dupé, et le mien n'est même pas noir ou de cette taille.
cole

2

Second Life LSL

animation début de l'image alpha de la tortue (clic droit ci-dessous pour enregistrer l'image)
tortue.png
fin de l'image alpha de la tortue (clic droit ci-dessus pour enregistrer l'image)

construction de l'objet: création d'
une taille de cylindre de racine <1, 1, 0.01> tranche 0.49, 0.51, couleur < 0, 0, 0>
faites la description de ce cylindre "8,1,1,1" sans les guillemets (très important)
faites un cylindre, nommez-le "cyl", couleur <0.25, 0.25, 0.25> alpha 0.5
dupliquer le cyl 48 fois
créer une boîte, nommez-la "sphère", couleur <1, ​​1, 1> transparence 100 sauf pour la transparence supérieure 0
placez la texture de votre tortue sur la face 0 de la boîte, la tortue doit faire face à + x
dupliquer la boîte 48 fois
sélectionnez toutes les boîtes et les cylindres, assurez-vous de sélectionner le cylindre racine en dernier,lien (contrôle L)

mettez ces 2 scripts à la racine:

//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);
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.