呼吸时间!


14

旋转描记器是一种抽取次摆线和次摆线的玩具。对于这个挑战,我们将只关注下摆线。

来自维基百科

下摆线是由与半径为r的圆相连的点围绕半径为R的固定圆的内部滚动而形成的轮盘赌,其中该点为距内部圆心的距离d

它们的参数方程式可以定义为:

在此处输入图片说明

在此处输入图片说明

其中θ是由水平和滚动圆的中心形成的角度。


您的任务是编写一个程序,绘制上面定义的点所跟踪的路径。作为输入,您将获得R rd,所有介于1和200之间的整数(包括1和200)。

您可以从标准输入,参数或用户输入中接收此输入,但是不能将其硬编码到程序中。您可以以最方便的方式接受它;如字符串,整数等。

假设:

  • 输入单位以像素为单位。
  • R > = r

输出应该是输入定义的下摆线的图形表示。不允许使用ASCII或其他基于文本的输出。该图像可以保存到文件或显示在屏幕上。包括输出的屏幕截图或图像,以供您选择输入。

您可以根据对比度限制为路径/背景选择任何喜欢的颜色。这两种颜色必须具有至少相差一半的HSV“值”分量。例如,如果您要从中测量HSV [0...1],则至少应有0.5差异。两者之间[0...255]应该有最小的128差异。


这是一个代码高尔夫,源代码的最小大小以字节为单位。


我们可以假设R > r还是R ≥ r?(同为rd。)
马丁安德

10
恭喜您发布了第2000个问题!;-)
门把手

@ m.buettner R>=r,但不限dr,并且可以在1-200范围内的任何位置。
Geobits,2014年

我们在谈论哪种分辨率?
凯尔·坎诺斯

@KyleKanos由于输入以像素为单位,并且每个像素的上限为200,因此,它不应大于798x798 R=200, r=1, d=200。您可以根据需要将图像调整为输入的大小,也可以将其保持恒定大小,只要它是可见的即可。
Geobits,2014年

Answers:


8

Mathematica,120个字节

f[R_,r_,d_]:=ParametricPlot[p#@t+#[-p*t/r]d&/@{Cos,Sin},{t,0,2r/GCD[p=R-r,r]Pi},PlotRange->400,ImageSize->800,Axes->0>1]

未经处理的代码和示例输出: 在此处输入图片说明

如果可以将坐标轴包括在图中,则可以再保存9个字符。


5

的JavaScript(ECMAScript的6) - 312个 314字符

document.body.appendChild(e=document.createElement("canvas"))
v=e.getContext("2d")
n=(e.width=e.height=800)/2
M=Math
P=2*M.PI
t=0
p=prompt
r=p('r')
R=p('R')-r
d=p('d')
X=x=>n+R*M.cos(t)+d*M.cos(R/r*t)
Y=x=>n+R*M.sin(t)-d*M.sin(R/r*t)
v.beginPath()
v.moveTo(X(),Y())
for(;t<R*P;v.lineTo(X(),Y()))t+=P/2e4
v.stroke()

JSFIDDLE

示例输出

r = 1,R = 200,d = 30

在此处输入图片说明


我喜欢它,但是ikt有点折断了。尝试例子R.
edc65

最后一行可能是for(; t <R * P; v.lineTo(X(),Y()))t + = P / R
edc65

@ edc65在这些示例中,它没有做足够的迭代来进行完整的轮换,所以还不错。我将迭代次数从9 * PI增加到R * 2 * PI,它应该更好(但是,我将增量保留在PI / 1000上,否则对于较小的R值会中断)。
MT0

3

蟒蛇:579

摘要

考虑到Mathematica的答案,这根本没有竞争力,但是我还是决定将其发布,因为图片很漂亮,并且可能会启发某人或对某人有用。因为它太大了,所以我基本上没有打高尔夫球了。该程序期望命令行输入为R,r,d。

屏幕截图

这是两个示例,一个用于(5,3,5),一个用于(10,1,7) 例子5-3-5 示例10-1-7

import math
import matplotlib.pyplot as P
from matplotlib.path import Path as H
import matplotlib.patches as S
import sys
a=sys.argv
(R,r,d)=int(a[1]),int(a[2]),int(a[3])
v=[]
c=[]
c.append(H.MOVETO)
t=0
while(len(v)<3 or v.count(v[-1])+v.count(v[-2])<3):
 p=t*math.pi/1000
 t+=1
 z=(R-r)*p/r
 v.append((round((R-r)*math.cos(p)+d*math.cos(z),3),round((R-r)*math.sin(p)-d*math.sin(z),3)))
 c.append(H.LINETO)
c.pop()
v.append((0,0))
c.append(H.CLOSEPOLY)
f=P.figure()
x=f.add_subplot(111)
x.add_patch(S.PathPatch(H(v,c)))
l=R+d-r
x.set_xlim(-l-1,l+1)
x.set_ylim(-l-1,l+1)
P.show()

2
可以调整比例吗?图像似乎是垂直压缩的。
AL

3

Perl / Tk中- 239 227

use Tk;($R,$r,$d)=@ARGV;$R-=$r;$s=$R+$d;$c=tkinit->Canvas(-width=>2*$s,-height=>2*$s)->pack;map{$a=$x;$b=$y;$x=$s+$R*cos($_/=100)+$d*cos$_*$R/$r;$y=$s+$R*sin($_)-$d*sin$_*$R/$r;$c->createLine($a,$b,$x,$y)if$a}0..628*$s;MainLoop

R = 120,r = 20,d = 40:

R = 120,r = 20,d = 40

R = 128,r = 90,d = 128:

R = 128,r = 90,d = 128

R = 179,r = 86,d = 98:

R = 179,r = 86,d = 98


2

处理中,270

import java.util.Scanner;
void setup(){size(500, 500);}
Scanner s=new Scanner(System.in);
int R=s.nextInt(),r=s.nextInt(),d=s.nextInt();
void draw(){
  int t=width/2,q=(R-r);
  for(float i=0;i<R*PI;i+=PI/2e4)
    point(q*sin(i)-d*sin(i*q/r)+t,q*cos(i)+d*cos(i*q/r)+t);
}

输入是通过控制台输入的,每行一个数字。

R = 65,r = 15,d = 24的屏幕截图: 在此处输入图片说明


2

GeoGebra,87岁

也就是说,如果您认为GeoGebra是有效的语言。

R=2
r=1
d=1
D=R-r
Curve[D*cos(t)+d*cos(D*t/r),D*sin(t)-d*sin(D*t/r),t,0,2π*r/GCD[D,r]]

接受来自GeoGebra输入栏,在格式输入<variable>=<value>,例如R=1000

请注意,您可能需要手动更改缩放大小才能查看整个图像。

屏幕截图

(窗口底部的内容是我正在谈论的输入栏)

在这里在线尝试。


1
我想这与Kyle Kanos提交内容有相同的限制,您不能指定像素大小吗?
马丁·恩德

@ m.buettner是的,您说对了...错过了
user12205 2014年

2

HTML + Javascript 256286303

编辑已 删除的第一个对moveTo的调用,无论如何它都可以工作。可以节省更多的切割beginPath,但是只有在第一次时才有效

Edit2 30个已保存的字节@@ΛΛҐӍΛПҒЦꝆ

<canvas id=c></canvas>R,r,d:<input oninput="n=400;c.width=c.height=t=n+n;v=c.getContext('2d');s=this.value.split(',');r=s[1],d=s[2],R=s[0]-r;v.beginPath();for(C=Math.cos,S=Math.sin;t>0;v.lineTo(n+R*C(t)+d*C(R/r*t),n+R*S(t)-d*S(R/r*t)),t-=.02);v.stroke()">

测试

将输入文本框(逗号分隔),然后按Tab

R,r,d:<input onchange="n=400;c.width=c.height=t=n+n;v=c.getContext('2d');s=this.value.split(',');r=s[1],d=s[2],R=s[0]-r;v.beginPath();for(C=Math.cos,S=Math.sin;t>0;v.lineTo(n+R*C(t)+d*C(R/r*t),n+R*S(t)-d*S(R/r*t)),t-=.02);v.stroke()"><canvas id=c></canvas>


1
您不能只是向画布添加一个ID并在全局范围内使用该ID,而不必使用querySelector!
Mama Fun Roll

@couldΛҐӍΛПҒЦꝆyeeeeees我可以。这是我在2014
5

哇,这比我想象的节省了更多的字节。
Mama Fun Roll

2

R,80个字节

f=function(R,r,d){a=0:1e5/1e2;D=R-r;z=D*exp(1i*a)+d*exp(-1i*D/r*a);plot(z,,'l')}

但是,如果要“干净”的图形(没有轴,没有标签等),则代码将必须稍长(88个字符):

f=function(R,r,d)plot((D=R-r)*exp(1i*(a=0:1e5/1e2))+d*exp(-1i*D/r*a),,'l',,,,,,'','',,F)

使用较长版本的f的一个代码示例:

f(R<-179,r<-86,d<-98);title(paste("R=",R,", r=",r," d=",d,sep=""))

一些示例输出:

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明


这不会采用像素输入大小,对吗?第一个示例应该几乎是第二个示例的三倍。
Martin Ender 2014年

为什么所有的,??
plannapus 2014年

逗号用于分隔参数,其中许多为NULL(无)。这里使用位置参数匹配来减少代码的长度。这当然是不好的编码习惯。推荐的方法是使用命名参数列表,例如type =“ l”,xlabel =“”等(并消除多余的逗号!)。
冯军

1

C#813,当时是999

需要减少字节数的工作。我设法减少了一点。它从控制台接受三个以空格分隔的整数。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
class P:Form
{
int R,r,d;
P(int x,int y,int z) {R=x;r=y;d=z;}
protected override void OnPaint(PaintEventArgs e)
{
if(r==0)return;
Graphics g=e.Graphics;
g.Clear(Color.Black);
int w=(int)this.Width/2;
int h=(int)this.Height/2;
List<PointF> z= new List<PointF>();
PointF pt;
double t,x,y;
double pi=Math.PI;
for (t=0;t<2*pi;t+=0.001F)
{
x=w+(R-r)*Math.Cos(t)+d*Math.Cos(((R-r)/r)*t);
y=h+(R-r)*Math.Sin(t)-d*Math.Sin(((R-r)/r)*t);
pt=new PointF((float)x,(float)y);
z.Add(pt);
}
g.DrawPolygon(Pens.Yellow,z.ToArray());
}
static void Main()
{
char[] d={' '};
string[] e = Console.ReadLine().Split(d);
Application.Run(new P(Int32.Parse(e[0]),Int32.Parse(e[1]),Int32.Parse(e[2])));
}
}

输出样本:

旋描仪


1

外壳脚本+ gnuplot(153​​)

大多数工作是卸下轴和tic,设置大小和范围,并提高精度。幸运的是,gnuplot对于打高尔夫球很自然,因此可以省略大多数命令。要保存字符,必须将输出手动重定向到图像文件。

gnuplot<<E
se t pngc si 800,800
se pa
se sa 1e4
uns bor
uns tic
a=$1-$2
b=400
p[0:2*pi][-b:b][-b:b]a*cos($2*t)+$3*cos(a*t),a*sin($2*t)-$3*sin(a*t) not
E

spiro.sh 175 35 25>i.png给出的方式 调用脚本在此处输入图片说明


1

R,169个字符

f=function(R,r,d){png(w=2*R,h=2*R);par(mar=rep(0,4));t=seq(0,R*pi,.01);a=R-r;x=a*cos(t)+d*cos(t*a/r);y=a*sin(t)-d*sin(t*a/r);plot(x,y,t="l",xaxs="i",yaxs="i");dev.off()}

缩进:

f=function(R,r,d){
    png(w=2*R,h=2*R) #Creates a png device of 2*R pixels by 2*R pixels
    par(mar=rep(0,4)) #Get rid of default blank margin
    t=seq(0,R*pi,.01) #theta
    a=R-r
    x=a*cos(t)+d*cos(t*a/r)
    y=a*sin(t)-d*sin(t*a/r)
    plot(x,y,t="l",xaxs="i",yaxs="i") #Plot spirograph is a plot that fits tightly to it (i. e. 2*R by 2*R)
    dev.off() #Close the png device.
}

例子:

> f(65,15,24)

在此处输入图片说明

> f(120,20,40)

在此处输入图片说明

> f(175,35,25)

在此处输入图片说明


1

SmileBASIC,96个字节

INPUT R,Q,D
M=R+MAX(Q,D)
S=R-Q@L
GPSET M+S*COS(I)+D*COS(S/Q*I),M+S*SIN(I)-D*SIN(S/Q*I)I=I+1GOTO@L

输入:50,30,50:

在此处输入图片说明


1

Befunge-98,113个字节

&&:00p-10p&20p"PXIF"4(10g'd:*:I10v>H40gF1+:"}`"3**`>jvI@
1(4"TURT"p04/d'*g02I/g00*p03/d'*g<^-\0/g00*g01:Fg03H:<0P

该代码依靠定点数学(FIXP)指纹进行一些三角计算,并使用Turtle Graphics(TURT)指纹绘制描记器的路径。

Befunge中的Turtle Graphics在行为上与Logo编程语言中的图形非常相似。您可以使用“乌龟”(用作笔)进行绘制,并围绕输出表面进行操纵。这需要将乌龟朝向特定方向,然后指示其向前移动一定距离。

为了使用该系统,我需要将原始的呼吸描记器方程式调整为对乌龟更友好的东西。我不确定这是否是最好的方法,但是我想出的算法是这样的:

ratio = (R-r)/r
distance1 = sin(1°) * (R-r)
distance2 = sin(1° * ratio) * d
foreach angle in 0° .. 36000°:
  heading(angle)
  forward(distance1)
  heading(-ratio*angle)
  forward(distance2)

请注意,这实际上以一种Z字形模式绘制了路径,但是除非您放大图像,否则您不会真正注意到。

这是使用参数R = 73,r = 51,d = 45的示例。

在此处输入图片说明

我已经使用CCBIcfunge测试了代码,两者均以SVG图像的形式产生输出。由于这是一种可缩放的矢量格式,因此生成的图像没有这样的像素大小-只是可以缩放以适合屏幕大小(至少在浏览器中查看时)。上面的示例是手动裁剪和缩放的屏幕截图。

从理论上讲,代码也可以在Rc / Funge上运行,但是在那种情况下,您需要在具有XWindows的系统上运行,因为它将尝试在窗口中呈现输出。


0

wxMaxima:110

f(R,r,d):=plot2d([parametric,(p:R-r)*cos(t)+d*cos(t*(p)/r),(p)*sin(t)-d*sin(t*(p)/r),[t,0,2*%pi*r/gcd(p,r)]]);

这是通过进行的交互式会话中调用的f(#,#,#)。作为示例,请考虑f(3,2,1)

在此处输入图片说明


虽然我喜欢漂亮的输出,但是我不确定这是“ 1到200之间的整数”还是“以像素给出”的方式。
Geobits,2014年

输入可以是整数或浮点数,wxMaxima仍将转换为浮点数以完成其工作,我将使用整数更新图像。我还必须考虑更多有关像素输入的信息。
Kyle Kanos 2014年

是的,我认为它将在内部进行转换,这不是问题。输入的整数约束主要是为了使闭环更容易(它们看起来更好imo)。
Geobits,2014年

0

球拍

#lang racket/gui
(require 2htdp/image)

(define frame (new frame%
                   [label "Spirograph"]
                   [width 300]
                   [height 300]))

(define-values (R r d) (values 50 30 10)) ; these values can be adjusted;

(new canvas% [parent frame]
     [paint-callback
      (lambda (canvas dc)
        (send dc set-scale 3 3)
        (for ((t (in-range 0 (* 10(* R pi)) 1)))
          (define tr (degrees->radians t))
          (define a (- R r))
          (define x (+ (* a (cos tr))
                       (* d (cos (* tr (/ a r))))))
          (define y (- (* a (sin tr))
                       (* d (sin (* tr (/ a r))))))
          (send dc draw-ellipse (+ x 50) (+ y 50) 1 1)))])

(send frame show #t)

输出:

在此处输入图片说明

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.