制作圆形错觉动画


84

您的工作是使这种圈子错觉动起来。看起来像点在圆内旋转,但实际上它们只是沿直线移动。

在此处输入图片说明

标准

  • 结果必须是动画的。制作动画的方式无关紧要,它可以生成.gif,可以绘制到窗口,某些设备屏幕或其他任何内容。
  • 这是一次人气竞赛,因此您可能需要向程序中添加一些其他功能,以获得更多的赞誉,例如改变分数。
  • 获胜者是上次提交有效作品后7天获得最高评价的有效答案。
  • 实际将实现点沿直线而不是其他方式移动的答案受到更多欢迎

“获胜者是7天后获得的最高评价”。那么,如果有人每隔6天发布某件事,直到星星消失,我们就没有赢家了吗?
凯文L

3
@KevinL不太可能发生,与您每6天从该问题获得的最高票数相比,我认为那15位额外代表并不那么重要。
Martin Ender 2014年

1
有时我想知道是否有人为了完成工作而这样做?
Daniel Pendergast 2014年

3
“看起来圆点内部旋转着,但实际上它们只是在直线上移动。”或者,也许它们确实在圆内旋转并且似乎在直线上移动……
coredump 2014年

1
无法..让这动画..我的脑子..尤其是三点式!
2014年

Answers:


126

Python 3.4

使用乌龟模块。乌龟的颜色不同,它们始终面对相同的方向,因此只要关注其中一只就可以很容易看出它们沿直线运动。尽管如此,圈子的幻想仍然很强烈。

11只海龟

即使只有3或4只乌龟,这种错觉仍然显得很强烈:

3只海龟4只乌龟

对于所有这些GIF示例,帧速率都已大大降低,但似乎并没有降低这种错觉。在本地运行代码可以使动画更流畅。

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


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


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


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


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


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


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


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

为了进行对比,以下是一些确实轮换的内容:

23圈海龟23只三叶龟

...还是他们?

该代码可以使用5个可选参数运行:填充,分辨率,循环,翻转和线条。

  • population 是海龟的数量
  • resolution 是时间分辨率(每个重复的动画帧数)
  • loops确定海龟向自身循环的次数。默认值1给出一个标准的圆,其他奇数给出该串乌龟中的循环数,而偶数给出一连串乌龟在末端断开,但仍带有弯曲运动的错觉。
  • flip如果非零,则导致海龟在回程时翻转方向(如庇护所建议的那样,以便它们从不向后移动)。默认情况下,它们保持固定方向,以避免端点产生视觉干扰。
  • lines 如果非零,则显示海龟移动的线,以与问题中的示例图像保持一致。

flipset的示例(带有和不带有)lines。我将上面的主要示例保留为没有翻转,因为我不希望有零星的跳跃,但是在所有海龟对齐的情况下,圆的边缘看起来确实更平滑,因此人们可以选择运行时喜欢的哪种样式编码。

11只带翻盖和线条的海龟11只海龟与翻转

上面的图像是如何用相同的代码生成的,可能不会立即显而易见。尤其是进一步向上的图像,它具有较慢的外循环和较快的内循环(看起来像是有人意外掉下的心形)。如果有人想延迟尝试/思考的时间,我在下面隐藏了对此的解释。

通过将循环数设置为15并将乌龟数设置为23(太低而无法表示15个循环)来创建具有不同大小的内部和外部循环的动画。使用大量乌龟会导致15个清晰定义的循环。使用过多的海龟会导致锯齿(与图像处理和渲染相同的原因)。试图代表过高的频率会导致显示较低的频率,并产生失真。

尝试使用不同的数字,我发现其中一些失真比对称的原件更有趣,因此我想在此处包括一个...


18
我喜欢乌龟。
FreeAsInBeer 2014年

18
我为海龟炮击+1
MrEngineer13

@ProgramFOX感谢语法突出显示!我在帮助和meta中进行了搜索,并说服自己使我们在代码高尔夫上没有突出显示语法-我现在对此感到非常高兴。
trichoplax 2014年

1
@aslum可以直接做出更改,但是我希望冻结他们的方向以真正强调他们不会偏离直线路线。也许我应该将其作为选项添加到代码中,以便人们可以选择他们喜欢的方法。
trichoplax

4
+1-看到一支游行乐队演奏其中一些时髦的歌曲真是太棒了!
mkoistinen 2014年

96

C

结果:

在此处输入图片说明

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

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

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

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

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

            if (i < hlen) continue;

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

        Sleep(100);
    }

    return 0;
}

3
在某些帧中,它有些偏离。但是,恭喜您使用ASCII进行编码!
justhalf 2014年

10
ASCII和+1system("cls"); // xD
ChristophBöhmwalder2014年

1
这很漂亮。
trichoplax

1
这在Linux上有效。(尽管很惨)
2014年

强制性的仇恨评论:“这不是C!该标准未定义Sleep,COORD或SetConsoleCursorPosition!”
immibis 2014年

52

SVG(无Javascript)

JSFiddle链接在这里

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

嗯,我敢肯定这会通过规则,但是我个人对您实际上相反却感到失望。而不是“看起来像这些点在圆内旋转,但实际上它们只是在直线上移动。”,您的工具是:“看起来像这些点在圆内运动,但是实际上它们在直线上移动。只是在圆圈内旋转。”
mkoistinen 2014年

最流畅的答案!
德里克·朕会功夫2014年

14
@mkoistinen我明白您的意思,但是这些点确实在直线移动。刚好通过两次旋转来计算它们的位置就更容易了:-)
挤压骨2014年

您是“手动”完成所有操作,还是使用任何类型的(非文本)编辑器?
瑕疵的

5
@flawr我只是在手机中使用了纯文本编辑器和计算器来计算出数字:-)
sosamrage ossifrage

47

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

intervaltime更改FPS(FPS = 1000 /间隔时间)。
balls更改#个球。
maxstep调整循环中的#步,则“平滑”越大。64应该足够大,使其看起来平滑。

建模为圆周移动,而不是沿直线移动球,但是视觉效果(应该是?)相同。有些代码很冗长,但这不是高尔夫代码,所以...

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

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

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

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

    step++;
}

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

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

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

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

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

2
太顺利了!非常好。
nneonneo 2014年

5
不要对动画使用setInterval,requestAnimationFrame而是使用。 使用修改了JSFiddlerequestAnimationFrame
klingt.net 2014年

1
只需进行一些参数调整,您就会获得完全不同的结果
FreeAsInBeer 2014年

@KevinL是的,也注意到了这一点。更新。
FreeAsInBeer 2014年

1
@FreeAsInBeer哦,当您说的非常不同时,我想您的意思就像jsfiddle.net/z6vhD/100
Kevin L

41

CSS动画

仅使用css动画的解决方案(请参阅JSFiddle上的动画-请注意,我在小提琴中添加了特定于浏览器的前缀,以便它可以在最新版本中使用)。

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


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

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

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

3
小提琴无法在最新的Chrome浏览器上为我工作= /
mkoistinen 2014年

1
@mkoistinen-要在不同的浏览器中运行,必须添加不同的前缀。(-webkit-对于基于Webkit的和基于-moz-Mozilla的)这是相同的小提琴,带有更新的前缀:jsfiddle.net/nBCxz/3
Derek朕会功夫

@mkoistinen你是对的。新的小提琴会添加所有必要的浏览器前缀,并可以在最新的Chrome上运行。
2014年

原始链接文本只是缺少右括号-仍然可以很好地使用,只是在需要修复时通知您(我不能更改,因为它不能少于6个字符)。
trichoplax

35

Mathematica

这是一个非常简单的提交。

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

如果您致电,animateCircle[32]您将获得包含32条直线和圆的整洁动画。

在此处输入图片说明

在Mathematica中它是完全平滑的,但我不得不对GIF的帧数进行一些限制。

现在,如果每行放两张光盘会发生什么?(即,添加Disk[-Sin[t + phase]*line, 0.05]到中的列表Map。)

在此处输入图片说明

您也可以将它们异相90度(使用Cos代替-Sin):

在此处输入图片说明


我不知道您是什么意思,可能您需要更改{t, 0, 2 \[Pi]}为,{t, 0, 2 \[Pi] - 2 \[Pi]/60, 2 \[Pi]/60}以便不会有两个相同的帧并更改AnimateTable。然后,您将能够导出GIF。
2014年

@swish不,它实际上使不存在的其他行变得奇怪,并且将光盘放置在不应该存在的位置(以及它们永远不会出现在的实际结果中Animate)。我会尝试Table再次使用。
马丁·恩德

@swish可行。我以为昨天尝试过类似的方法,但显然没有。
马丁·恩德

25

VBScript + VBA + Excel饼图

这会使您的处理器略微哭泣,但看起来很漂亮,我相信它可以按照规格工作。我使用@Fabricio的答案作为实现圆运动算法的指南。

编辑:进行了一些调整,以提高渲染速度。

饼图的屏幕截图

编码:

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

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

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

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

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

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

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

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

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

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

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

它在第81行崩溃,错误80070057,“具有给定名称的元素不存在”或类似的东西(从匈牙利语翻译回来,这就是为什么我不知道确切的错误消息)。
marczellm 2014年

Szervusz,@ marczellm。当图表处于“动画”状态时,单击图表外部时,可以重现该错误。您必须让它聚焦,否则程序将出错。否则,可能是由于与Office不兼容。我在Win7上使用Office 2010。
舒适地

Office 2007,Win7。在我看来,图表根本没有得到关注。
marczellm 2014年

21

Excel,161字节

电子表格

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

A2(周期)确定完整“革命”的时间(秒)。

行中的每个单元格都是与相应行的值有关的基本条件。例如,K2为:

 =1*(A5=7)

中央单元格(K9)为:

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

通过在随机单元格上按住“删除”来强制动画以不断触发刷新。

我知道这是一个古老的话题,但是最近的活动使它达到了顶峰,并且出于某种原因似乎很有吸引力。长时间的pcg侦听器,首次呼叫者。要温柔。


哇,这真是不可思议,您可以使用Excel:D
Beta Decay

15

只是为了与PSTricks一起玩。

在此处输入图片说明

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

\psset{unit=.3}

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

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

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

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

11

Fortran

使用以下位置的Fortran gif模块将每个帧创建为单独的gif文件:http : //fortranwiki.org/fortran/show/writegif
然后,我通过使用ImageMagick将单独的gifs合并为一个动画gif进行了一点欺骗。

Fortran

更新:设置新= .true。得到以下内容:

在此处输入图片说明

program circle_illusion

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

implicit none

logical,parameter :: new = .false.

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

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

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

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

do k=0,355,time_sep

    !clear entire image:
    pixel = white      

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

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

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

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

end do

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

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

contains

    subroutine draw_square(r,c,icolor)

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

    integer,parameter :: d = 10 !square size

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

    end subroutine draw_square

    subroutine draw_circle(r,c,icolor,d)

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

    integer :: i,j

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

    end subroutine draw_circle

    subroutine convert(xy,row,col)

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

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

    end subroutine convert

    subroutine spherical_to_cartesian(r,theta,xy)

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

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

    end subroutine spherical_to_cartesian

end program circle_illusion

1
我喜欢垂直和水平元素的“挤压”效果。
波特兰赛跑者2014年

11

强制性C64版本。

在您喜欢的模拟器中复制并粘贴:

C64版本

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

10

紧凑的javascript版本,将默认设置更改为其他设置

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

HTML:

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

JavaScript:

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

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

}

2
你做了...一个甜甜圈?实际上,您的动画带有较小的点看起来不错(尝试bw=10)。请编辑您的答案以显示您的代码。哦,要解决这个问题,您应该修复一个错误:在Trig计算中替换time+i*0.39*0.29time+i*Math.PI/num,以便对于的任何值正确计算坐标num。(PS 在此更新了JSFiddle。欢迎访问codegolf.stackexchange.com)
吱吱作响的ossifrage

我只是想做出一些不同的事情(像乌龟一样)。这里的新手是在代码高尔夫中的:)哦,谢谢您使用公式:DI急忙尝试了随机值,并没有停止一分钟就得出了正确的公式:P
Diego


4

我对榆树的看法。我是一个初学者,很乐意接受PR来改进此解决方案(GitHub):

在此处输入图片说明

请注意,此提交实际上是直线上的移动点:

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
那个光标骗了我很好,我的甚至都不是黑色或那个大小。
2015年

2

第二人生LSL

动画 乌龟alpha图像的起点(右键单击下方以保存图像)
turtle.png
乌龟alpha图像的起点(右键单击上方以保存图像)

构建对象:
生成根基本圆柱体大小<1、1、0.01>切片0.49、0.51,颜色< 0,0,0>
对该圆柱的描述不带引号(非常重要)为“ 8,1,1,1”(非常重要),
将其命名为“ cyl”,颜色< 0.25、0.25、0.25 > alpha 0.5
复制cyl 48次
创建一个框,将其命名为“ sphere”,颜色< 1、1、1 >透明度100,但顶部透明度0
将乌龟纹理放置在该框的表面0上,乌龟应该面对+ x
复制该框48次
选择所有框和圆柱体,确保最后选择根圆柱体,链接(控件L)

将以下两个脚本放在根目录中:

//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);
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.