Epiklonların çizimi


22

Bir episikloid , bir daire üzerindeki bir noktanın, başka bir daire etrafında dönerken yaptığı bir eğridir. Bir siklog , düzlem boyunca yuvarlanırken normal bir çokgenin üzerindeki bir noktanın şeklidir . Bir episikloon , normal bir poligondaki bir noktadan izlenen eğridir.

Verilen bir epicyclogon çeken bir program yazın r, r1, r2, n1, n2:

r = number of clockwise revolutions rolling polygon makes around stationary polygon (any real number as limited by float values) 
r1 = distance from center of stationary polygon to each of its vertices (positive real number)
r2 = distance from center of rolling polygon to each of its vertices (positive real number)
n1 = number of sides stationary polygon has (integer greater than 2)
n2 = number of sides rolling polygon has (integer greater than 2)

notlar

  • rNegatif olduğunda , silindir saat yönünün tersine gitmelidir .
  • Zira r, bir devrim, iki şeklin centroidlerini bağlayan çizgi tam 360 derece süpürdüğünde meydana gelir. Bu kavram tüm değerlerini içerecek şekilde genişletilmiştir r. (Yani çeyrek devrede, santroidleri birbirine bağlayan çizgi 90 derece süpürür.)
  • Bu argümanlar komut satırından gelmeli veya programınız onlardan isteymelidir (örn. Python ile input()).
  • r1ve r2görüntünün boyutları değil, birbirlerine göredir. Böylece bir "birimi" istediğiniz sayıda gerçek piksel olarak ayarlayabilirsiniz.

İzlemeniz gereken nokta, yuvarlanma şeklinin köşelerinden biridir. Şekiller, bu köşe ile sabit bir tepe noktasına ve bitişik iki tarafa değecek şekilde başlamalıdır:

epiksikon örneği

Tam başlangıç ​​köşeleri ve sabit poligonun açısı önemli değil.

Çıktı

Çıktı en az 600x600 piksel (veya 600 olarak ayarlanabilen değişken boyutta) bir görüntüye gitmelidir. Görüntüde iyi çerçevelenmiş olan, parametreler tarafından belirtilen tüm epikliniği eğrisi göstermelidir.

Yuvarlanma ve sabit çokgenler de çizilmelidir (rulo son haliyle). İki şekil ve epiklik, gözle görülür şekilde farklı üç renkte olmalıdır.

Ayrıca basit bir yolu olmalı değil çokgenler (değişikliği çizmek trueiçin falsekod kısıtlamasını fazla olarak).

Lütfen bize en az 2 çıkış resmi gösterin. Gerekirse onları küçültmek sorun değil.

puanlama

Geçerli çıktı görüntüleri üreten en kısa kod kazanır.

Bonuslar

  • Çıktı çizilen eğrinin animasyonlu bir gif (veya benzeri) olması durumunda eksi 50 bayt.
  • Eksi 150 byte izin halinde n1ve n2şekiller uzunluğunun hat kesimleri olmak çok değeri 2 alır 2 * r1(ya da r2) birbirleri etrafında, "döner". Centroidler diğer durumlarda olduğu gibi birbirleri etrafında dönmediklerinden, rne zaman n1ve n22 yaşında olmanız nasıl size bağlıdır . (Hiç "yuvarlanma" değil, onu ele almak sayılmaz.)

Bu yeni fikrin iyi uygulandığını görmek için oldukça istekli olduğum için (ve tam olarak bir çakal değil), kazanana 150 ödül temsilcisi ödeyeceğim. Yarışma aynı gün ödül sona erecek.

Kodun çoğunu başka bir gönderimden yeniden yazdıkları açıksa, ödül kazanana verilmez.

Zaten bunu yapan kütüphane işlevlerine (varsa) izin verilmez.

Not: Bu , herkesin göndermekte özgür olduğu artık sorularımdan geldi . Ama eğer hiç kimse onlara mesaj göndermezse, zamanında geleceğim için iyi bir şans var. : P


Ben saat yönünün tersine olumlu olması gerektiğini düşünüyorum.
Soham Chowdhury

3
@SohamChowdhury Bence pek önemli değil.
Calvin'in Hobileri,

Aslında haklısın. Örnek resimlerin var mı? CDF çalarım yok.
Soham Chowdhury

@githubphagocyte Amacınızı anlıyorum. Sabit.
Calvin'in Hobileri

@ MartinBüttner Çok katı değil, düşündüğüm ilk şeydi. Gerektiğinde değerleri başka bir şekilde isteyebilirsiniz.
Calvin'in Hobileri

Yanıtlar:


3

MATLAB: 735 bayt - 200 bonus = 535

Programım n = 2 durumunu ele alıyor ve gerçek zamanlı bir animasyon çiziyor. Golf ve ungolfed versiyonları arasında birkaç fark vardır:

Ungolfed versiyonu sadece savegif = 1kodu ayarlayarak animasyonu 'g.gif' dosyasına kaydetme seçeneğine sahiptir . Bazı nedenlerden dolayı sinir bozucu olabileceğinden varsayılan olarak kapalıdır:

  • İstenmeyen bir dosyanın oluşturulması
  • Olası gecikme
  • Birden fazla monitörünüz varsa ve arsa penceresi doğru pencerede değilse bir hata oluşur ... Bonus sürümünün aşılmasıyla yaklaşık 100 bayt süren gif tasarrufunun golf versiyonuna bırakılması gerekiyordu.

Topraksız versiyon izleyici tepe noktasına bir daire çizer. Aynı zamanda daha fazla kare üretir ve daha hızlı hareket eder (ancak golf sürümünde sayıları değiştirerek ayarlanabilir).

Örnekler:

f(11,5,90,2,99,0) program sonlandırıldıktan sonra

golflü örnek

epic(1.3,4,2,6,6,1) gif çıkışı ile

asılsız örnek

Ungolfed kod

%epicyclogon animation outputs to 'g.gif' if savegif=1 as well as animating in real time

function[] = epic(r,r1,r2,n1,n2,dispPoly)

savegif = 0;  %set to 1 to write .gif

cs = @(a) [cos(a);sin(a)];
vert = @(r, n, v) r * cs(2*pi*v/n);
polyPt = @(l, s, n, r) vert(r, n, floor(l/s)) + mod(l/s,1)*(vert(r, n, floor(l/s)+1) - vert(r, n, floor(l/s)));
polyPt2 = @(i, f, n, r) vert(r, n, i) + f*(vert(r, n, i+1) - vert(r, n, i));
rotm = @(a) [cos(a) -sin(a);sin(a) cos(a)];
arrpluspt = @(a, p) a + kron(p, ones(1,length(a)));
arg = @(p) atan2(p(2), p(1));

E = 1e-9;

dispPoly = dispPoly / dispPoly;

sgn = sign(-r);
r = abs(r);

s1 = 2*r1*sin(pi/n1);
s2 = 2*r2*sin(pi/n2);

%d1 = (r1*r1 - s1*s1*.25)^.5;
d2 = (r2*r2 - s2*s2*.25)^.5;

plotmax = r1+2*r2;

astep = .05; %determines amount of frames per rotation
delay = .01; % time per frame

l = 0;

lRem = 0;
lr = 0;

P1 = vert(r1, n1, 1:n1+1) * dispPoly; 
trace = [];

first = 1;
while 1

    if lr %exists while rotating about a corner of the stationary
        rotA = 2*pi/n1;
    else
        rotA = 2*pi/n2;
    end
    rotPt = polyPt(l, s1, n1, r1);
    lb = l + lRem;
    side1 = floor(l / s1 - E);
    side1up = side1 + lr;
    p2cen = polyPt2(side1, lb/s1 -side1 - .5 * s2/s1, n1, r1) + d2 * cs(2*pi*(side1+.5)/n1);
    if first
        p2cen0 = p2cen;
        r = r + arg(p2cen0)/(2*pi);
    end

    for a = 0:astep:rotA    
        P2 = vert(r2, n2, 0:n2);
        P2 = rotm( pi +pi/n1 -pi/n2   +2*pi*side1/n1) * P2;
        P2 = arrpluspt(P2, p2cen);
        P2 = arrpluspt(P2, -rotPt);
        P2 = rotm(a) * P2;
        P2 = arrpluspt(P2, rotPt);
        trV = mod(floor(l/s2 + E) + lr, n2) + 1;

        cen = rotm(a) * (p2cen - rotPt) + rotPt;
        trace = [trace,P2(:,trV)]; 

        plot(P1(1,:), sgn*P1(2,:), P2(1,:)*dispPoly, sgn*P2(2,:)*dispPoly, trace(1,:),sgn*trace(2,:),P2(1,trV), sgn*P2(2,trV),'o');

        %plot(P1(1,:), P1(2,:), P2(1,:), P2(2,:), trace(1,:),trace(2,:),...
        %[0,p2cen0(1)],[0,p2cen0(2)],[0,cen(1)],[0,cen(2)], P2(1,trV), P2(2,trV),'o');

        axis([-plotmax,plotmax,-plotmax,plotmax]);
        axis square
        figure(1);
       if savegif
           drawnow
           frame = getframe(1); % plot window must be on same monitor!
           img = frame2im(frame);
           [img1,img2] = rgb2ind(img,256);
       end
       if first
           if savegif
               imwrite(img1,img2,'g','gif','DelayTime',2*delay); %control animation speed(but not really)
           end
           first = 0;
       else
           if savegif
               imwrite(img1,img2,'g','gif','WriteMode','append','DelayTime', 2*delay);
           end
       end
       pause(.01);

        adf = mod(arg(cen) - r*2*pi, 2*pi);
        if adf < astep & l/(n1*s1) + .5 > r
            return
        end

    end

%cleanup for next iteration 
    jump = lRem + ~lr * s2; 
    lnex = l + jump; 

    if floor(lnex / s1 - E) > side1up 
        lnex = s1*(side1up+1);
        lRem = jump - (lnex - l);
        lr = 1;
    else    
        lRem = 0;
        lr = 0;
    end
    l = lnex;
end

Golf kodu

function[]=f(r,h,H,n,N,d)
P=pi;T=2*P;F=@floor;C=@(a)[cos(a);sin(a)];g=@(i,f,n,r)r*C(T*i/n)*(1-f)+f*r*C(T*(i+1)/n);R=@(a)[C(a),C(a+P/2)];W=@(a,p)[a(1,:)+p(1);a(2,:)+p(2)];b=@(p)atan2(p(2),p(1));E=1e-9;d=d/d;S=1-2*(r>0);r=-r*S;x=2*h*sin(P/n);X=2*H*sin(P/N);M=h+2*H;l=0;z=0;L=0;A=h*C(T*(0:n)/n)*d;t=[];while 1
v=l/x;D=F(v-E);q=g(D,v-D,n,h);Z=D+L;c=g(D,v+z/x-D-.5*X/x,n,h)+H*cos(P/N)*C(T*D/n+P/n);r=r+~(l+L)*b(c)/T;for a=0:.1:T/(L*n+~L*N)
O=@(p)W(R(a)*W(p,-q),q);B=O(W(R(P+P/n-P/N+T*D/n)*H*C(T*(0:N)/N),c));t=[t,B(:,mod(F(l/X+E)+L,N)+1)];plot(A(1,:),S*A(2,:),d*B(1,:),d*S*B(2,:),t(1,:),t(2,:)*S)
axis([-M,M,-M,M],'square');pause(.1);if.1>mod(b(O(c))-r*T,T)&v/n+.5>r
return;end;end;j=z+~L*X;J=l+j;L=F(J/x-E)>Z;l=L*x*(Z+1)+~L*J;z=L*(J-l);end

Talimatlar:

İşlevi aynı ada sahip bir dosyaya kaydedin, yani epic.mveya f.m. Fonksiyonu Matlab konsolundan çağırarak çalıştırın.

Kullanım: epic(r, r1, r2, n1, n2, dispPoly) nerede dispPolybir Boole değişkeni (eğer yanlışsa sıfır, doğru değilse sıfır olmayan bir sayı) çokgenlerin çizilip çizilmeyeceğini belirler.

Düzenleme: animasyonlu görüntü için 50 bonus eklendi.


14

Java - 2,726 2,634 - 200 = 2434 karakter

3800 ish bayttan geliştirildi

Önerileriniz için herkese teşekkürler (özellikle takma adı117), işte yeni sürüm.

ArrayList'i genişleten nokta sınıfı ve L sınıfı olan bir P sınıfı ekledim.

Ayrıca bazı küçük mantık değişiklikleri de ekledim.

İşte ana sınıf (golf oynamayan değil):

import java.awt.*;
import java.awt.geom.*;

import javax.swing.*;
public class Polygons2 extends JPanel{
    public static void main(String[] args) throws InterruptedException{new Polygons2(args);}
    double q=Math.PI*2;
    int d=1;
    public Polygons2(String[] args) throws InterruptedException{
        double revolutions=Double.valueOf(args[0])*q;
        double stationaryRadius = Double.valueOf(args[1]);
        double rollingRadius = Double.valueOf(args[2]);
        int stationarySides = Integer.valueOf(args[3]);
        int rollingSides = Integer.valueOf(args[4]);    
        double dist = stationaryRadius+rollingRadius+70;
        P sp = new P(dist,dist);
        P rp = new P(sp.x,sp.y-rollingRadius-stationaryRadius);
        //get points for rolling polygon and stationary polygon
        int key=0;
        for(double stationaryAngle=-q/4;stationaryAngle<q-q/4;stationaryAngle+=q/stationarySides){
            P p=new P(Math.cos(stationaryAngle)*stationaryRadius+sp.x,Math.sin(stationaryAngle)*stationaryRadius+sp.y);
            p.k=key;key++;
            stationaryPoints.add(p);
        }
        for(double rollingAngle=q/4;rollingAngle<q+q/4;rollingAngle+=q/rollingSides){
            P p=new P(Math.cos(rollingAngle)*rollingRadius+rp.x,Math.sin(rollingAngle)*rollingRadius + rp.y);
            p.k=key;key++;
            rollingPoints.add(p);
        }
        double g=(q/2)-((q/2-(q/rollingSides))/2) - ((q/2-(q/stationarySides))/2)-.05;
        for(P p:rollingPoints){p.r(getPoint(0), g);}
        //set up JFrame
        JFrame f = new JFrame();
        f.add(this);
        f.setSize((int)dist*2+60,(int)dist*2+60);
        f.setVisible(true);
        int[] pKeys= new int[]{stationaryPoints.get(0).k,rollingPoints.get(0).k};
        int index=1;
        P rc = rollingPoints.c();
        P sc =stationaryPoints.c();
        double currentRadian=Math.atan2(rc.y-sc.y,rc.x-sc.x);
        double totalRadian = 0;
        while(Math.abs(totalRadian)<revolutions){
            P rc2 = rollingPoints.c();
            P sc2 =stationaryPoints.c();
            double angle = Math.atan2(rc2.y-sc2.y,rc2.x-sc2.x);
            if(currentRadian-angle<2){totalRadian+=(angle-currentRadian);}
            currentRadian=angle;
            L clone=(L)path.clone();
            clone.add(new P(rollingPoints.get(1).x,rollingPoints.get(1).y));
            path = clone;
            for(P p:rollingPoints){
                p.r(getPoint(pKeys[index]),.01);
                int size = stationaryPoints.size();
                for(int i=0;i<size;i++){
                    P stationaryPointAtI = stationaryPoints.get(i);
                    P nextPoint=null;
                    if(i==size-1){nextPoint=stationaryPoints.get(0);}
                    else{nextPoint=stationaryPoints.get(i+1);}
                    if(p.b(stationaryPointAtI, nextPoint)==1&&containsKey(pKeys,p.k)==0){
                        //rolling point is between 2 stationary points
                        if(index==1){index=0;}else{index=1;}
                        pKeys[index]=p.k;
                    }
                    int size2=rollingPoints.size();
                    for(int h=0;h<size2;h++){
                        P nextPoint2=null;
                        if(h==size2-1){nextPoint2=rollingPoints.get(0);}
                        else{nextPoint2=rollingPoints.get(h+1);}
                        if(stationaryPointAtI.b(rollingPoints.get(h), nextPoint2)==1&&containsKey(pKeys,stationaryPointAtI.k)==0){
                            //stationary point is between 2 rolling points
                            if(index==1){index=0;}else{index=1;}
                            pKeys[index]=stationaryPointAtI.k;
                        }
                    }
                }
            }
            repaint();
            Thread.sleep(5);
        }
    }
    volatile L path = new L();
    L rollingPoints = new L();
    L stationaryPoints = new L();
    P getPoint(int key){
        for(P p:rollingPoints){if(p.k==key){return p;}}
        for(P p:stationaryPoints){if(p.k==key){return p;}}
        return null;
    }
    int containsKey(int[] keys,int key){
        for(int i:keys){if(key==i){return 1;}}
        return 0;
    }
    @Override
    public void paintComponent(Graphics g){
        Path2D.Double sPath = new Path2D.Double();
        sPath.moveTo(stationaryPoints.get(0).x, stationaryPoints.get(0).y);
        for(P p:stationaryPoints){
            sPath.lineTo(p.x, p.y);
        }
        sPath.closePath();
        Path2D.Double rPath = new Path2D.Double();
        rPath.moveTo(rollingPoints.get(0).x, rollingPoints.get(0).y);
        for(P p:rollingPoints){
            rPath.lineTo(p.x, p.y);
        }
        rPath.closePath();
        g.setColor(Color.white);
        g.fillRect(0,0,getWidth(),getHeight());
        Graphics2D t = (Graphics2D)g;
        if(d==1){
        t.setColor(Color.black);
        t.draw(sPath);
        t.setColor(Color.blue);
        t.draw(rPath);
        }
        g.setColor(Color.green);
        for(P p:path){g.fillOval((int)p.x-1, (int)p.y-1, 2, 2);}
    }
}

Ve golf versiyonu:

import java.awt.*;import java.awt.geom.*;import javax.swing.*;import static java.lang.Math.*;class Polygons2Golfed extends JPanel{public static void main(String[]a)throws Exception{new Polygons2Golfed(a);}double q=PI*2;int d=1;public Polygons2Golfed(String[]a)throws Exception{double b,c,f;b=Double.valueOf(a[1]);c=Double.valueOf(a[2]);int d,e;d=Integer.valueOf(a[3]);e=Integer.valueOf(a[4]);f=b+c+100;P o=new P(f,f);P r=new P(o.x,o.y-c-b);int s=0;for(double u=-q/4;u<q-q/4;u+=q/d){P p=new P(cos(u)*b+o.x,sin(u)*b+o.y);p.k=s;s++;l.add(p);}for(double u=q/4;u<q+q/4;u+=q/e){P p=new P(cos(u)*c+r.x,sin(u)*c+r.y);p.k=s;s++;k.add(p);}double g=q/e/2+q/d/2-.05;for(P p:k){p.r(v(0),g);}JFrame j=new JFrame();j.add(this);j.setSize((int)f*2+60,(int)f*2+60);j.setVisible(true);m=new int[]{l.get(0).k,k.get(0).k};int ad=1;P rc=k.c();P sc=l.c();double ab,ac;ab=atan2(rc.y-sc.y,rc.x-sc.x);ac=0;while(abs(ac)<Double.valueOf(a[0])*q){P rc2=k.c();P sc2=l.c();double ah=atan2(rc2.y-sc2.y,rc2.x-sc2.x);if(ab-ah<2)ac+=(ah-ab);ab=ah;L ag=(L)n.clone();ag.add(new P(k.get(1).x,k.get(1).y));n=ag;for(P p:k){p.r(v(m[ad]),.01);int af=l.size();for(int i=0;i<af;i++){P aa=l.get(i);P w=null;if(i==af-1){w=l.get(0);}else{w=l.get(i+1);}if(p.b(aa, w)==1&&w(p.k)==0){if(ad==1)ad=0;else ad=1;m[ad]=p.k;}int ae=k.size();for(int h=0;h<ae;h++){P u=null;if(h==ae-1)u=k.get(0);else u=k.get(h+1);if(aa.b(k.get(h),u)==1&&w(aa.k)==0){if(ad==1)ad=0;else ad=1;m[ad]=aa.k;}}}}repaint();Thread.sleep(5);}}L n=new L();L k=new L();L l=new L();P v(int key){for(P p:k){if(p.k==key)return p;}for(P p:l){if(p.k==key)return p;}return null;}int[]m;int w(int key){for(int i:m){if(key==i)return 1;}return 0;}@Override public void paintComponent(Graphics g){Path2D.Double aq=new Path2D.Double();aq.moveTo(l.get(0).x,l.get(0).y);for(P p:l){aq.lineTo(p.x, p.y);}aq.closePath();Path2D.Double aw=new Path2D.Double();aw.moveTo(k.get(0).x, k.get(0).y);for(P p:k){aw.lineTo(p.x, p.y);}aw.closePath();g.setColor(Color.white);g.fillRect(0,0,getWidth(),getHeight());Graphics2D t=(Graphics2D)g;if(d==1){t.setColor(Color.black);t.draw(aq);t.setColor(Color.blue);t.draw(aw);}g.setColor(Color.green);for(P p:n){g.fillOval((int)p.x-1,(int)p.y-1,2,2);}}}

Sınıf P'nin yanı sıra:

import java.awt.geom.*;class P{double x,y;public P(double a,double b){x=a;y=b;}int k;void r(P c,double g){double a,r;a=Math.atan2(y-c.y,x-c.x)+g;r=Math.sqrt((c.x-x)*(c.x-x)+(c.y-y)*(c.y-y));x=Math.cos(a)*r+c.x;y=Math.sin(a)*r+c.y;}public int b(P a,P b){if(Line2D.ptSegDist(a.x,a.y,b.x,b.y,x,y)<.5)return 1;return 0;}}

Ve ben:

import java.util.*;public class L extends ArrayList<P>{public P c(){double x,y;x=0;y=0;for(P p:this){x+=p.x;y+=p.y;}return new P(x/size(),y/size());}}

Çokgenleri göstermek için int d'yi 0 veya 1 olarak değiştirin

Bağımsız Değişkenler - 1 100 50 5 2

görüntü tanımını buraya girin

args - 1,5 100 100 7 3

görüntü tanımını buraya girin

args - 2 40 100 3 7

görüntü tanımını buraya girin


rGerçekten bütün örneklerde 50? Bu, silindirin 50 kez döndüğü anlamına gelir.
Calvin'in Hobileri,

@ Calvin'sHobbies yeni örnek pi * 3 gösteriyor
Stretch Maniac

1
@StretchManiac Bu doğru olamaz. 3π sizi sabit poligonun etrafından 9 defa biraz fazla almalıdır.
Martin Ender

4
Sadece normal kodda RotatingPolygonsGolfediken sınıf adının "golf" kodunda ne kadar komik RotatingPolygons. ;)
Calvin'in Hobileri

1
sadece belirli sınıflar yerine * kullanmak üzere ithalatınızı değiştirerek karakter yığınından tasarruf edebilirsiniz ...
pseudonym117

12

Javascript, 1284 karakter (-200 = 1084 karakter)

Küçültülmüş kod

function epi(B,r2,r1,n2,n1){K=Math;function C(t){return K.cos(t)}function S(t){return K.sin(t)}function A(y,x){return K.atan2(y,x)}P=K.PI;v=[[],[]];w=[[],[]];z=[];function Z(x,y,j){c=C(t=f*H+P/2);s=S(t);v[j][n]=c*x-s*y;w[j][n]=s*x+c*y;}function E(i){return{x:r1*S(t=p-i*q),y:r1*C(t)};}function D(x,y,X,Y,t){L=A(m.y,m.x);M=K.sqrt(m.x*m.x+m.y*m.y);N=K.sqrt(X*X+Y*Y);O=~~(t*(M>N?M:N)+1);for(i=J;i<=O;i++){J=1;z[n]=f*H+P+t*i/O;Z(x+M*C(T=L+t*i/O),y+M*S(T),0);Z(x+N*C(T=A(Y,X)+t*i/O),y+N*S(T),1);n++}}function F(x,y,n,r,L,s){I.strokeStyle=s;I.beginPath();for(i=0;i<n;i++)I[i?'lineTo':'moveTo'](x+r*C(t=L+(1-2*i)*P/n),y+r*S(t)*W);I.closePath();I.stroke()}p=P/n1;q=2*p;u=P/n2;H=2*u;s2=r2*S(u);g=f=l=n=J=h=0;R=300;while(l<=(B*2+1)*P/H){o=E(0);m=E(h);m.y-=o.y;m.x-=o.x;if(g<s2){D(g,-r2*C(u),-o.x,-o.y,q);h=(h+1)%n1;g+=2*r1*S(p)}else{m.x+=g-s2;D(s2,-r2*C(u),-o.x+g-s2,-o.y,H);g-=s2*2;f=(f+1)%n2;l++}}return function(e_,t,aa,W_){W=aa?-1:1;I=(e=e_).getContext('2d');I.fillStyle='black';I.fillRect(0,0,600,600);W_&1&&F(R,R,n2,r2,0,'white');T=A(w[1][0],v[1][0]);U=V=0;I.strokeStyle='teal';I.beginPath();I.moveTo(R+v[0][0],R+w[0][0]*W);while(U<t){_=A(w[1][V+1],v[1][V+1]);U+=_-T+(_+1<T?2*P:0);T=_;V++;I.lineTo(R+v[0][V],R+w[0][V]*W)}W_&2&&I.stroke();W_&4&&F(R+v[1][V],R+w[1][V]*W,n1,r1,z[V],'red')}}

Tam kod

function epi( nr, r2, r1, n2, n1 ) {
function C( t )
    { return Math.cos( t ); }
function S( t )
    { return Math.sin( t ); }
function A( dy, dx )
    { return Math.atan2( dy, dx ); }

var iCCW, e, t_, xs = [[],[]], ys = [[],[]], ts = [], n = 0, iArc0 = 0;

function addpt( x, y, iBin ) {
    var c_ = C(t_ = iFrame*t2 + Math.PI/2 ),
        s_ = S(t_);

    xs[iBin][n] = c_*x-s_*y;
    ys[iBin][n] = s_*x+c_*y;
}

function poly1pt( iP )
    { return { x: r1*S(t_ = t1b2-iP*t1), y: r1*C(t_) }; }

function arc1( P_Arc_, xP_, yP_, xC_, yC_, t ) {
    var dx_, dy_, dxC, dyC;
    var t0 = A( dy_ = P_Arc_.y, dx_ = P_Arc_.x ),
        r_ = Math.sqrt( dx_*dx_ + dy_*dy_ ),
        t0C = A( dyC = yC_, dxC = xC_ ),
        rC = Math.sqrt( dxC*dxC + dyC*dyC ),
        nt = ~~(t*(r_>rC?r_:rC)+1);

    for( var i = iArc0; i <= nt; i++ ) {
        iArc0 = 1;
        ts[n] = iFrame*t2 + Math.PI + t*i/nt;
        addpt( xP_ + r_*C(t_ = t0+t*i/nt), yP_ + r_*S(t_), 0 );
        addpt( xP_ + rC*C(t_ = t0C+t*i/nt), yP_ + rC*S(t_), 1 );
        n++;
    }
}

function poly( x,y, n, r, t0, sColor ) {
    var Cx = e.getContext('2d');
    Cx.strokeStyle = sColor;
    Cx.beginPath();
    for( var i = 0; i < n; i++ )
        Cx[i ? 'lineTo' : 'moveTo']( x + r*C(t_ = t0+(1-2*i)*Math.PI/n), y + r*S(t_)*iCCW );

    Cx.closePath();
    Cx.stroke();
}

var t1b2 = Math.PI/n1,
    t1 = 2*t1b2,
    t2b2 = Math.PI/n2,
    t2 = 2*t2b2,
    s1 = 2*r1*S(t1b2),
    s2 = 2*r2*S(t2b2),
    xPivot = 0,
    iPivot = 0,
    iFrame = 0,
    P_Pivot, P_Arc,
    nFrame = 0;

while( nFrame <= (nr*2+1)*Math.PI/t2 ) {
    P_Pivot = poly1pt( 0 );
    P_Arc = poly1pt( iPivot );
    if( xPivot < s2/2 ) {
        P_Arc.x -= P_Pivot.x;
        P_Arc.y -= P_Pivot.y;
        arc1( P_Arc, xPivot, -r2*C(t2b2), -P_Pivot.x, -P_Pivot.y, t1 );
        iPivot = (iPivot+1) %n1;
        xPivot += s1;
    } else {
        P_Arc.x -= (P_Pivot.x - (xPivot - s2/2));
        P_Arc.y -= P_Pivot.y;
        arc1( P_Arc, s2/2, -r2*C(t2b2), -P_Pivot.x + xPivot - s2/2, -P_Pivot.y, t2 );
        xPivot -= s2;
        iFrame = (iFrame+1) %n2;
        nFrame++;
    }
}

function renderTo( eCanvas, t, isCCW, sWhat ) {
    iCCW = isCCW ? -1 : 1;
    var Cx = (e = eCanvas).getContext('2d');
    Cx.fillStyle = 'black';
    Cx.fillRect( 0,0, 600,600 );

    if( sWhat &1 )
        poly( 300,300, n2, r2, 0, 'white' );

    var tRef = A( ys[1][0], xs[1][0] ),
        tCum = 0,
        i0 = 0;

    Cx.strokeStyle = 'green';
    Cx.beginPath();
    Cx.moveTo( 300+xs[0][0], 300+ys[0][0]*iCCW );
    while( tCum < t ) {
        t_ = A( ys[1][i0+1], xs[1][i0+1] );
        tCum += t_ - tRef + (t_ - tRef < -1 ? 2*Math.PI : 0);
        tRef = t_;
        i0++;
        Cx.lineTo( 300+xs[0][i0], 300+ys[0][i0]*iCCW );
    }
    if( sWhat &2 )
        Cx.stroke();
    if( sWhat &4 )
        poly( 300+xs[1][i0], 300+ys[1][i0]*iCCW, n1, r1, ts[i0], 'red' );
}

return renderTo;
}

Tüm poligon zaferiyle rutinin farkına varacak (ve animasyonu gösterecek) bir keman bulundu.

http://jsfiddle.net/7rv751jy/2/embedded/result/

Komut epi, OP'de listelenen beş parametreyi kabul eden bir fonksiyon tanımlar . argümanları kabul epieden imzalı bir işlev döndürür (e,t,isCCW,flags):

  • e - oluşturulacak olan 600x600 HTML5 kanvaslık bir öğeye başvuru
  • t- İkinci poligonun orta kısmının, ilkinin orta kısmı etrafında kaydırması gereken toplam açı (radyan cinsinden). Girilen argüman, geçen rotasyon sayısının 2 pi katını geçmemelidir epi.
  • isCCW - izin saatin tersi yönde ilerlemesinin gerekip gerekmediğini belirten boolean (saat yönünde olanın aksine)
  • flags - hangi elemanların oluşturulması gerektiğini gösteren bir dizi bit bayrağı
    • bit 1 - ayarlanmışsa çokgen 1'i oluşturma
    • bit 2 - ayarlanmışsa izlemeyi oluşturma
    • bit 3 - ayarlanmışsa çokgen 2 oluşturma

İşlev, çeşitli argüman kümeleriyle istediğiniz zaman çağrılabilir.

Bazı notlar:

  • Rutin, n1 = 2ve / veya nerede dejenere durumları ele alır n2 = 2. Animasyon yaparken, belirli uzunluk kombinasyonları izlemede hızlıca hızlı ilerlemelere neden olur. Bunun nedeni, animasyon karelerinin, ikinci poligonun merkeze açılı olarak indekslenmesi ve dtata poly2 / d teta sentroidin, 2-taraflı poli 2'nin sentroidinin, 2-taraflı poli 1'in tepe noktasına yakın olduğu durumlarda tekil hale gelmesidir. Ancak bu, izi etkilemez.

  • İçindeki parametre adları epigeliştirme boyunca kafa karıştırıcı görünecek. Çokgen 1'i "2" ve çokgen 2'yi "1" olarak adlandırdım. Sözleşmedeki ve OP’ninki arasındaki tutarsızlığı fark ettiğimde, koddaki tüm indeksleri değiştirmek yerine, sadece argümanların sırasını değiştirdim epi.

  • Yukarıdaki keman jQuery'yi içe aktarır, ancak bu kullanıcı arayüzünü idare etmektir. epiFonksiyon hiçbir kütüphane bağımlılıkları vardır.

  • Kod, CCW izlerini basitçe Y eksenini tersine çevirerek işler. Poligon 2, CCW izleri sırasında Y ters çevrilmiş bir pozisyonda başladığından beri bu biraz garip, ancak kimse rutinin şık olması gerektiğini söylemedi. ;)


1
Güzel! Tam ekran bağlantısını çalışmanın en kolay yolu buldum: jsfiddle.net/7rv751jy/embedded/result
Calvin'in Hobileri

Küçük bir şikayet, izleyici tepe noktasının sabit bir tepe üzerinde başlamamasıdır.
Calvin'in Hobileri

Ha. Teknik özelliklerde bunu tamamen göz ardı ettim. 'Ha' diyorum, çünkü kod aslen (istemeden) belirtildi, ancak iz tepe noktasını değiştirdim çünkü iz hemen başlarsa izinin daha iyi görüneceğini düşündüm. Kodu, teknik özellikleri belirtecek şekilde güncelledim ve kemanın bağlantısını tam ekran özelliklerine uyumlu bir sürüme güncelledik. Bir bonus olarak, toplam sayının bir karakterini çalıyor.
COTO

Biraz hızlandırabilir miyim? JS noob burada.
Soham Chowdhury

@SohamChowdhury: Kodu nt = ~~(t*(r_>rC?r_:rC)+1)değiştirin nt = ~~(t*(r_>rC?r_:rC)/10+1)ve işleri biraz hızlandırması gerekir.
COTO
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.