Vẽ Epicyclogons


22

Một epicycloid là đường cong một điểm trên một vòng tròn tạo ra khi nó cuộn quanh một vòng tròn khác. Một cyclogon là hình dạng một điểm trên một đa giác thông thường tạo ra khi nó lăn trên một mặt phẳng. Một epicyclogon là đường cong được vạch bởi một điểm trên một đa giác thông thường khi nó cuộn quanh một điểm khác.

Viết một chương trình thu hút một epicyclogon cho 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)

Ghi chú

  • Khi râm là con lăn nên đi ngược chiều kim đồng hồ .
  • Đối với r, một cuộc cách mạng xảy ra khi đường nối giữa tâm của hai hình quét ra hết 360 độ. Khái niệm này được mở rộng để bao gồm tất cả các giá trị của r. (Vì vậy, trong một phần tư cuộc cách mạng, đường nối giữa tâm sẽ quét ra 90 độ.)
  • Các đối số này phải xuất phát từ dòng lệnh hoặc chương trình của bạn sẽ nhắc cho chúng (ví dụ với Python input()).
  • r1r2có liên quan với nhau, không phải kích thước của hình ảnh. Vì vậy, bạn có thể đặt một "đơn vị" là bất kỳ số pixel thực tế nào.

Điểm bạn phải tìm ra là một trong những đỉnh của hình dạng lăn. Các hình phải bắt đầu với đỉnh này chạm vào một đỉnh cố định và hai cạnh kề nhau:

ví dụ epicyclogon

Các đỉnh bắt đầu chính xác và góc của đa giác đứng yên không quan trọng.

Đầu ra

Đầu ra phải đi đến một hình ảnh có ít nhất 600x600 pixel (hoặc một số kích thước thay đổi có thể được đặt thành 600). Nó phải hiển thị toàn bộ đường cong epicyclogon được chỉ định bởi các tham số, được đóng khung tốt trong hình ảnh.

Các đa giác lăn và cố định cũng phải được rút ra (với con lăn ở trạng thái cuối cùng). Hai hình dạng và epicyclogon nên có ba màu khác nhau đáng chú ý.

Ngoài ra còn phải là một cách đơn giản để không vẽ đa giác (một sự thay đổi trueđể falsetrong cũng đủ code).

Vui lòng cho chúng tôi xem ít nhất 2 hình ảnh đầu ra. Bạn có thể thu nhỏ chúng nếu cần thiết.

Chấm điểm

Mã ngắn nhất tạo ra hình ảnh đầu ra hợp lệ sẽ thắng.

Tiền thưởng

  • Trừ 50 byte nếu đầu ra là một gif hoạt hình (hoặc tương tự) của đường cong được vẽ.
  • Trừ đi 150 byte nếu bạn cho n1n2lấy giá trị 2 để các hình dạng trở thành các đoạn có độ dài 2 * r1(hoặc r2), "lăn" xung quanh nhau. Cách bạn xử lý rkhi nào n1n22 là tùy thuộc vào bạn vì các nhân mã không xoay quanh nhau như cách họ làm trong các trường hợp khác. (Không "lăn" chút nào không được tính là xử lý nó.)

Vì tôi khá háo hức khi thấy ý tưởng mới lạ này được thực hiện tốt (và nó không chính xác là một cuộc thi làm bánh), tôi sẽ trao 150 tiền thưởng cho người chiến thắng. Cuộc thi sẽ kết thúc cùng ngày hết tiền thưởng.

Tiền thưởng sẽ không được trao cho người chiến thắng nếu rõ ràng họ chỉ đơn giản viết lại phần lớn mã từ một bài nộp khác.

Các chức năng thư viện đã xảy ra để làm điều này (nếu có) không được phép.

Lưu ý: Điều này xuất phát từ những câu hỏi còn sót lại của tôi mà bất cứ ai cũng có thể đăng miễn phí. Nhưng nếu không có ai đăng chúng thì sẽ có cơ hội tốt. : P


Tôi nghĩ ngược chiều nên tích cực thay thế.
Soham Chowdhury

3
@SohamChowdhury Tôi nghĩ nó hầu như không quan trọng.
Sở thích của Calvin

Bạn nói đúng, thực sự. Bạn có bất kỳ hình ảnh ví dụ? Tôi không có máy nghe nhạc CDF.
Soham Chowdhury

@githubphagocyte Tôi thấy quan điểm của bạn. Đã sửa.
Sở thích của Calvin

@ MartinBüttner Không quá khắt khe, đó chỉ là điều đầu tiên tôi nghĩ đến. Bạn có thể nhắc các giá trị theo cách khác nếu cần thiết.
Sở thích của Calvin

Câu trả lời:


3

MATLAB: 735 byte - 200 tiền thưởng = 535

Chương trình của tôi xử lý trường hợp n = 2 và vẽ hoạt hình thời gian thực. Có một vài sự khác biệt giữa các phiên bản golf và không có người lái:

Phiên bản không được chỉnh sửa chỉ có một tùy chọn để lưu hình ảnh động vào một tệp 'g.gif', bằng cách đặt savegif = 1mã. Nó được tắt theo mặc định vì nó có thể gây phiền nhiễu vì một số lý do:

  • Tạo một tệp không mong muốn
  • Độ trễ có thể
  • Một lỗi được tạo ra nếu bạn có nhiều màn hình và cửa sổ cốt truyện không ở bên phải ... Việc tiết kiệm gif phải được bỏ trong phiên bản golf vì nó mất khoảng 100 byte, vượt quá kích thước của phần thưởng.

Phiên bản không có hình vẽ một vòng tròn trên đỉnh tracer. Nó cũng tạo ra nhiều khung hình hơn và di chuyển nhanh hơn (mặc dù điều này có thể được điều chỉnh trong phiên bản golf bằng cách thay đổi số).

Mẫu:

f(11,5,90,2,99,0) sau khi kết thúc chương trình

mẫu golf

epic(1.3,4,2,6,6,1) với đầu ra gif

mẫu không có mẫu

Mã bị đánh cắp

%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

Mã đánh gôn

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

Hướng dẫn:

Lưu hàm vào một tệp có cùng tên, nghĩa là epic.mhoặc f.m. Chạy nó bằng cách gọi hàm từ bảng điều khiển Matlab.

Cách sử dụng: epic(r, r1, r2, n1, n2, dispPoly) trong đó dispPolymột biến Boolean (0 nếu sai, một số khác không nếu đúng) xác định có nên vẽ đa giác hay không.

Chỉnh sửa: Đã thêm 50 điểm thưởng cho hình ảnh hoạt hình.


14

Java - 2.726 2.634 - 200 = 2434 ký tự

Cải thiện từ 3800 byte ish

Cảm ơn tất cả những lời đề nghị của bạn (đặc biệt là bút danh 117), đây là phiên bản mới.

Tôi đã thêm một lớp P là lớp điểm và một lớp L mở rộng ArrayList

Tôi cũng đã thêm một số thay đổi logic nhỏ.

Đây là lớp học chính (không chơi gôn):

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

Và phiên bản chơi gôn:

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

Cũng như các lớp P:

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

Và tôi:

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

Thay đổi int d thành 0 hoặc 1 để hiển thị đa giác

đối số - 1 100 50 5 2

nhập mô tả hình ảnh ở đây

lập luận - 1.5 100 100 7 3

nhập mô tả hình ảnh ở đây

tranh luận - 2 40 100 3 7

nhập mô tả hình ảnh ở đây


rthực sự là 50 trong tất cả các ví dụ của bạn? Điều đó có nghĩa là con lăn đi khoảng 50 lần.
Sở thích của Calvin

Ví dụ mới của @ Calvin cho thấy pi * 3
Stretch Maniac

1
@StretchManiac Điều đó không thể đúng. 3π sẽ đưa bạn hơn 9 lần xung quanh đa giác đứng yên.
Martin Ender

4
Thật buồn cười khi tên lớp nằm RotatingPolygonsGolfedtrong mã "được đánh gôn" trong khi nó chỉ là RotatingPolygonsmã thông thường. ;)
Sở thích của Calvin

1
bạn có thể lưu một đoạn ký tự tốt chỉ bằng cách thay đổi nhập khẩu của mình để sử dụng * thay vì các lớp cụ thể ...
bút danh

12

Javascript, 1284 ký tự (-200 = 1084 ký tự)

Mã rút gọn là

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

Mã đầy đủ là

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

Một bí ẩn để thấy thói quen trong tất cả vinh quang đa thê của nó (và để chứng minh hoạt hình) được tìm thấy tại

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

Kịch bản lệnh xác định một hàm được gọi là epichấp nhận năm tham số được liệt kê trong OP. epitrả về một hàm có chữ ký (e,t,isCCW,flags)chấp nhận đối số:

  • e - tham chiếu đến phần tử canvas HTML5 600x600 để kết xuất
  • t- tổng góc (tính bằng radian) mà tâm của đa giác thứ hai sẽ quét xung quanh tâm của hình thứ nhất. Đối số được truyền vào không được vượt quá 2 lần số lần quay được chuyển đến epi.
  • isCCW - boolean cho biết liệu dấu vết có nên tiến hành theo hướng ngược chiều kim đồng hồ hay không (ngược với chiều kim đồng hồ)
  • flags - một tập hợp các cờ bit cho biết phần tử nào sẽ được hiển thị
    • bit 1 - kết xuất đa giác 1 nếu được đặt
    • bit 2 - hiển thị dấu vết nếu được đặt
    • bit 3 - kết xuất đa giác 2 nếu được đặt

Hàm có thể được gọi bất kỳ số lần nào với các đối số khác nhau.

Một số lưu ý:

  • Các thường trình xử lý các trường hợp thoái hóa trong đó n1 = 2và / hoặc n2 = 2. Khi hoạt hình, sự kết hợp nhất định của độ dài sẽ gây ra những tiến bộ nhanh chóng đột ngột trong dấu vết. Điều này là do các khung hình động được lập chỉ mục theo góc tới tâm của đa giác thứ hai và d theta poly2 / d theta centroid trở thành số ít trong trường hợp tâm của poly 2 2 cạnh nằm gần một đỉnh của poly 1 2 Tuy nhiên, điều này không ảnh hưởng đến dấu vết.

  • Các tên tham số trong episẽ có vẻ khó hiểu vì trong suốt quá trình phát triển, tôi đã gọi đa giác 1 là "2" và đa giác 2 là "1". Khi tôi nhận ra sự không nhất quán giữa quy ước của tôi và OP, thay vì hoán đổi tất cả các chỉ số trong mã, tôi chỉ cần hoán đổi thứ tự của các đối số trong đó epi.

  • Fiddle ở trên nhập jQuery, nhưng điều này là để xử lý UI. Các epichức năng không có người phụ thuộc thư viện.

  • Mã xử lý các dấu vết CCW bằng cách đảo ngược trục Y. Điều này có phần không phù hợp vì đa giác 2 bắt đầu ở vị trí đảo ngược Y trong các dấu vết CCW, nhưng không ai nói rằng thói quen phải thanh lịch. ;)


1
Đẹp! Tôi đã tìm thấy liên kết toàn màn hình dễ nhất để làm việc với: jsfiddle.net/7rv751jy/embedded/result
Sở thích của Calvin

Một khiếu nại nhỏ là đỉnh của tracer không bắt đầu trên một đỉnh cố định.
Sở thích của Calvin

Hà. Tôi hoàn toàn bỏ qua điều đó trong thông số kỹ thuật. Tôi nói 'Ha' vì mã ban đầu (vô tình) với thông số kỹ thuật, nhưng tôi đã thay đổi đỉnh theo dõi vì tôi thấy dấu vết sẽ đẹp hơn nếu bắt đầu ngay lập tức. Tôi đã cập nhật mã để thông số kỹ thuật và cập nhật liên kết đến fiddle thành phiên bản tuân thủ thông số toàn màn hình. Như một phần thưởng, nó đánh bại một nhân vật trong tổng số.
COTO

Làm thế nào tôi có thể tăng tốc nó lên một chút? Noob ở đây.
Soham Chowdhury

@SohamChowdhury: Thay đổi mã nt = ~~(t*(r_>rC?r_:rC)+1)thành nt = ~~(t*(r_>rC?r_:rC)/10+1)và nó sẽ tăng tốc mọi thứ lên một chút.
COTO
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.