Spirograf Zamanı!


14

Spirograf, hipotrokoidleri ve epitrokoidleri çizen bir oyuncaktır. Bu meydan okuma için, sadece hipotrokoidlere odaklanacağız.

Gönderen Vikipedi :

Bir hipotrokoid, R yarıçapının sabit bir dairesinin içinde yuvarlanan bir yarıçap r dairesine bağlı bir nokta tarafından izlenen bir rulettir , burada nokta iç çemberin merkezinden d uzaklığı d'dir .

Onlar için parametrik denklemler şu şekilde tanımlanabilir:

resim açıklamasını buraya girin

resim açıklamasını buraya girin

Burada θ , yuvarlanma çemberinin yatay ve merkezinin oluşturduğu açıdır.


Göreviniz, yukarıda tanımlanan noktadan izlenen yolu çizecek bir program yazmaktır. Girdi olarak, 1, 200 dahil tüm tamsayılara R , r ve d verilir .

Bu girdiyi stdin, bağımsız değişkenler veya kullanıcı girdisinden alabilirsiniz, ancak programa sabit olarak kodlanamaz. Sizin için en uygun olan formda kabul edebilirsiniz; dizeler, tamsayılar vb.

varsayalım:

  • Giriş birimleri piksel olarak verilmiştir.
  • R > = r

Çıktı, girdi tarafından tanımlanan hipotrokoidin grafiksel bir temsili olmalıdır. ASCII veya başka bir metin tabanlı çıktıya izin verilmez. Bu görüntü bir dosyaya kaydedilebilir veya ekranda görüntülenebilir. Seçtiğiniz bir girdi için çıktının bir ekran görüntüsünü veya görüntüsünü ekleyin.

Kontrast kısıtlamasına tabi olarak, yol / arka plan için istediğiniz renkleri seçebilirsiniz. İki renk, ölçeğin en az yarısında HSV 'Değer' bileşenine sahip olmalıdır. Örneğin, HSV'yi ölçüyorsanız [0...1], en azından 0.5fark olmalıdır . Arasında [0...255]minimum bir 128fark olmalı .


Bu bir kod golf, bayt cinsinden minimum kaynak kodu boyutu kazanır.


Varsayabiliriz R > rya R ≥ r? (Aynı için rve d.)
Martin Ender

10
2000. soruyu yayınladığınız için tebrikler! ;-)
Kapı tokmağı

@ m.buettner R>=r, ancak dbununla sınırlı değildir rve 1-200 aralığında herhangi bir yerde olabilir.
Geobits

Ne tür bir çözümden bahsediyoruz?
Kyle Kanos

@KyleKanos Girdi piksel cinsinden olduğundan ve her birinin 200 kapağı olduğundan, verilen 798x798 değerinden daha büyük olmamalıdır R=200, r=1, d=200. İsterseniz görüntüyü girdiye göre boyutlandırabilir veya görünebilir olduğu sürece sabit bir boyutta tutabilirsiniz.
Geobits

Yanıtlar:


8

Mathematica, 120 bayt

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]

Kod çözülmemiş kod ve örnek çıktı: resim açıklamasını buraya girin

Eksenleri grafiğe ekleyebilirsem, 9 karakter daha kaydedebilirim.


5

JavaScript (ECMAScript 6) - 312 314 Karakter

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

Örnek Çıktı

r = 1, R '= 200, d = 30

resim açıklamasını buraya girin


Sevdim ama bir şekilde kırıldı.
R'deki

Son satır (; t <R * P; v.lineTo (X (), Y ())) t + = P / R için
edc65

@ edc65 Bu örneklerde tam bir döndürme yapmak için yeterli yineleme yapmadığı kırık değil. Yinelemeleri 9 * PI'den R * 2 * PI'ye artırdım ve daha iyi olmalı (ancak, PI / 1000'deki artışı bıraktım, aksi takdirde küçük R değerleri için kırılacak).
MT0

3

Python: 579

özet

Bu Mathematica cevabı göz önüne alındığında hiç de rekabetçi değil, ama yine de göndermeye karar verdim çünkü resimler güzel ve birine ilham verebilir veya birine faydalı olabilir. Çok daha büyük olduğu için, temelde rahat bıraktım. Program R, r, d komut satırı girdisini bekler.

Ekran görüntüsü

İşte biri (5,3,5) ve biri (10,1,7) için örnek 5-3-5 örnek 10-1-7

kod

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
Oranı ayarlayabilir misiniz? Görüntünün dikey olarak sıkıştırıldığı anlaşılıyor.
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

İşleme, 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);
}

Giriş konsol başına, her satıra bir sayı girilir.

R = 65, r = 15, d = 24 için ekran görüntüsü: resim açıklamasını buraya girin


2

GeoGebra, 87

Yani, GeoGebra'yı geçerli bir dil olarak görüyorsanız.

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 giriş çubuğundan girişi <variable>=<value>, örn R=1000.

Görüntünün tamamını görüntülemek için zoom boyutunu manuel olarak değiştirmeniz gerekebileceğini unutmayın.

ekran görüntüsü

(Pencerenin altındaki şey bahsettiğim giriş çubuğudur)

Burada çevrimiçi deneyin .


1
Sanırım bu Kyle Kanos'un gönderimi ile aynı sınırlamaya sahip, boyutu piksel cinsinden belirtemiyor musunuz?
Martin Ender

@ m.buettner Evet haklısın ... bunu kaçırdın
user12205

2

HTML + Javascript 256286303

Düzenle MoveTo için 1. çağrı kaldırıldı, yine de çalışıyor. Daha fazla kesme başlangıcından tasarruf edebilir, ancak daha sonra ilk kez çalışır

Edit2 30 bayt thx kurtardı @ ӍѲꝆΛҐӍΛПҒЦꝆ

<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()">

Ölçek

Girişi metin kutusuna koyun (virgülle ayrılmış) ve ardından sekmesine basın

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
Sadece tuval için bir kimlik ekleyip bu kimliğini global olarak querySelector kullanmak zorunda değil misiniz?
Mama Fun Roll

@ ӍѲꝆΛҐӍΛПҒЦꝆ Instagram Hesabındaki Resim ve Videoları yeeeeees Mayıs 2014'te farkında olmadığım bir şey
edc65

Vay canına düşündüğümden daha fazla bayt kurtardı.
Mama Fun Roll

2

R, 80 bayt

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')}

Ancak, 'temiz' rakamlar istiyorsa (eksen yok, etiket yok vb.), Kodun biraz daha uzun olması gerekir (88 karakter):

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

F'nin daha uzun sürümünü kullanan bir kod örneği:

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

Bazı örnek çıktılar:

resim açıklamasını buraya girin

resim açıklamasını buraya girin

resim açıklamasını buraya girin


Bu, giriş boyutlarını piksel cinsinden almaz, değil mi? İlk örnek, ikincisinin neredeyse üç katı kadar büyük olmalıdır.
Martin Ender

Neden tüm ,??
plannapus

Virgül, birçoğu NULL (hiçbir şey) olmayan argümanları ayırmak için kullanıldı. Burada kodun uzunluğunu azaltmak için konumsal argüman eşleştirmesi kullanıldı. Bu elbette kötü kodlama uygulamasıdır. Önerilen yol, type = "l", xlabel = "", etc gibi adlandırılmış argüman listesini kullanmak (ve gereksiz virgüllerden kurtulmak!).
Feng

1

C # 813, 999 oldu

Bayt sayısını azaltmak için biraz çalışmaya ihtiyaç vardır. Biraz azaltmayı başardım. Konsoldan boşlukla ayrılmış üç tamsayıyı kabul eder.

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

Çıktı örnek:

Spirograph


1

kabuk betiği + gnuplot (153)

Çabaların çoğu eksenleri ve tikleri kaldırmak, boyutu ve aralığı ayarlamak ve hassasiyeti artırmaktır. Neyse ki, gnuplot golf için doğaldır, bu yüzden komutların çoğu kısaltılabilir. Karakterleri kaydetmek için çıktının bir görüntü dosyasına manuel olarak yönlendirilmesi gerekir.

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

Komut dosyasını spiro.sh 175 35 25>i.pngvermek resim açıklamasını buraya girin


1

R, 169 karakter

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()}

Girintili'ye:

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

Örnekler:

> f(65,15,24)

resim açıklamasını buraya girin

> f(120,20,40)

resim açıklamasını buraya girin

> f(175,35,25)

resim açıklamasını buraya girin


1

SmileBASIC, 96 bayt

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

Girdi: 50,30,50:

resim açıklamasını buraya girin


1

Befunge-98, 113 bayt

&&: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

Bu kod , bazı trigonometrik hesaplamalar için Sabit Nokta Matematik (FIXP) parmak izine ve spirografın yolunu çizmek için Kaplumbağa Grafikleri (TURT) parmak izine dayanır .

Befunge'deki Kaplumbağa Grafikleri, davranış olarak Logo programlama dilindeki grafiklere çok benzer . Çıktı yüzeyinin etrafına yönlendirdiğiniz bir 'kaplumbağa' ile çizim yaparsınız. Bu, kaplumbağayı belirli bir yöne yönlendirmeyi ve daha sonra belirli bir mesafeye ilerlemesini bildirmeyi gerektirir.

Bu sistemle çalışmak için orijinal spirograf denklemlerini biraz daha kaplumbağa dostu bir şeye ayarlamam gerekiyordu. Bunun en iyi yaklaşım olup olmadığından emin değilim, ancak bulduğum algoritma şöyle çalışıyor:

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)

Bunun aslında bir tür zikzak deseni ile yolu çizdiğini, ancak görüntüyü yakınlaştırmazsanız gerçekten fark etmediğinizi unutmayın.

İşte R = 73, r = 51, d = 45 parametrelerini kullanan bir örnek.

resim açıklamasını buraya girin

Her ikisi de bir SVG görüntüsü şeklinde çıktı üreten CCBI ve cfunge ile kodu test ettim . Bu ölçeklenebilir bir vektör biçimi olduğundan, elde edilen görüntünün piksel boyutu yoktur - sadece ekran boyutuna sığacak şekilde ölçeklendirilir (en azından bir tarayıcıda görüntülendiğinde). Yukarıdaki örnek, manuel olarak kırpılmış ve ölçeklendirilmiş bir ekran görüntüsüdür.

Teoride kod Rc / Funge üzerinde de çalışabilir , ancak bu durumda çıktıyı bir pencerede oluşturmaya çalışacağından XWindows ile bir sistemde çalışmanız gerekir.


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

Bu etkileşimli oturumda üzerinden çağrılır f(#,#,#). Örnek olarak f(3,2,1)şunları göz önünde bulundurun :

resim açıklamasını buraya girin


Ben güzel çıktı gibi, bunun nasıl "1 ile 200 arasında tamsayılar" veya "piksel olarak verilen" izlediğinden emin değilim.
Geobits

Giriş tamsayı veya kayan nokta olabilir, wxMaxima zaten işini yapmak için kayan noktaya dönüştürecek, tamsayı kullanarak bir görüntü güncelleyeceğim. Girdi hakkında daha çok piksel olarak düşünmem gerekecek.
Kyle Kanos

Evet, onları dahili olarak dönüştüreceğini düşündüm ve bu bir sorun değil. Girdi üzerindeki tamsayı kısıtlaması esas olarak kapalı döngülerin daha kolay hale getirilmesiydi (sadece daha iyi imo görünüyorlar).
Geobits

0

raket

#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)

Çıktı:

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.