에피 사이클로 곤 그리기


22

외측 구름 사이클로이드는 또 다른 원형 롤 주위로 원형상의 포인트가 만드는 곡선이다. cyclogon는 A의 점 형상 인 정다각형이 그 평면에 걸쳐 롤로 만든다. epicyclogon이 또 다른 롤 주위로 하나 정다각형에 점 추적 곡선이다.

주어진 epicyclogon을 그리는 프로그램을 작성 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)

노트

  • r음수 롤러 가야 반 시계 방향으로 .
  • 내용은 r, 하나의 회전이 발생할 경우 전체 360도에서 두 스윕 형상의 무게 중심을 연결하는 선. 이 개념은의 모든 값을 포함하도록 확장되었습니다 r. (따라서 1/4 회전에서 중심을 연결하는 선은 90도 튀어 나옵니다.)
  • 이 인수는 명령 행에서 가져 오거나 프로그램에서 프롬프트를 표시해야합니다 (예 : Python 's input()).
  • r1r2이미지의 서로 아니라 크기에 상대적이다. 따라서 하나의 "단위"를 실제 픽셀 수로 설정할 수 있습니다.

추적해야 할 점은 롤링 모양의 꼭짓점 중 하나입니다. 도형은이 꼭짓점이 고정 꼭짓점에 닿고 두면이 인접 해 있어야합니다.

epicyclogon 예

정확한 시작 정점과 고정 다각형의 각도는 중요하지 않습니다.

산출

출력은 600x600 픽셀 이상 (또는 600으로 설정할 수있는 일부 가변 크기)의 이미지로 이동해야합니다. 이미지에 잘 짜여진 매개 변수로 지정된 전체 에피 사이클로 곤 곡선을 표시해야합니다.

롤링 및 고정 폴리곤도 그려야합니다 (롤러가 최종 상태 임). 두 가지 모양과 epicyclogon은 눈에 띄게 다른 세 가지 색이어야합니다.

또한 간단한 방법이 있어야 하지 다각형 (의 변화 그릴 truefalse코드 접미사 인치).

최소 2 개의 출력 이미지를 보여주십시오. 필요한 경우 축소해도됩니다.

채점

유효한 출력 이미지를 생성하는 가장 짧은 코드가 이깁니다.

보너스

  • 출력이 그려지는 곡선의 애니메이션 GIF (또는 유사) 인 경우 빼기 50 바이트입니다.
  • 값을 2로 설정 n1하고 빼면 150 바이트를 빼면 n2모양이 길이 2 * r1(또는 r2)의 선분이 되어 서로 "롤링"됩니다. 당신이 처리하는 방법 rn1n2있는 무게 중심이가 다른 경우에는 어떻게 서로 다른 길을 주위에 회전하지 않기 때문에이 당신에게 달려 있습니다. (“롤링”이 아님은 처리하는 것으로 간주되지 않습니다.)

나는이 참신한 아이디어가 잘 실행되는 것을보고 싶어서 (그리고 그것은 정확히 케이크 워크가 아니다), 나는 150 개의 현상금 대표 를 승자 에게 수여 할 것이다. 컨테스트는 현상금이 소진 된 당일에 종료됩니다.

바운티는 단순히 다른 제출에서 코드의 대부분을 재 작성한 것이 확실한 경우 당첨자에게는 수여되지 않습니다.

이 작업을 이미 수행 한 라이브러리 기능 (있는 경우)은 허용되지 않습니다.

참고 : 이것은 누구나 자유롭게 게시 할 수있는 남은 질문 에서 나왔습니다 . 그러나 다른 사람이 게시하지 않으면 제 시간에 할 가능성이 높습니다. :피


반 시계 방향이 긍정적이어야한다고 생각합니다.
Soham Chowdhury

3
@SohamChowdhury 나는 그것이 중요하지 않다고 생각합니다.
Calvin 's Hobbies

실제로 그렇습니다. 이미지 예가 있습니까? CDF 플레이어가 없습니다.
Soham Chowdhury

@ githubphagocyte 당신의 요점을 참조하십시오. 결정된.
Calvin 's Hobbies

@ MartinBüttner 너무 엄격하지는 않지만 내가 처음으로 생각한 것입니다. 필요한 경우 다른 방법으로 값을 입력하도록 프롬프트 할 수 있습니다.
Calvin 's Hobbies

답변:


3

MATLAB : 735 바이트-200 보너스 = 535

내 프로그램은 n = 2 경우를 처리하고 실시간 애니메이션을 그립니다. 골프와 언 골프 버전 사이에는 몇 가지 차이점이 있습니다.

ungolfed 버전 savegif = 1에는 코드에서 설정하여 애니메이션을 파일 'g.gif'에 저장하는 옵션 만 있습니다 . 몇 가지 이유로 성 가실 수 있으므로 기본적으로 꺼져 있습니다.

  • 원치 않는 파일 생성
  • 가능한 지연
  • 여러 개의 모니터가 있고 플롯 창이 올바른 모니터에없는 경우 오류가 발생합니다 . gif 저장은 보너스 크기를 초과하는 약 100 바이트가 걸리므로 골프 버전에서 삭제해야했습니다.

ungolfed 버전은 트레이서 정점에 원을 그립니다. 또한 더 많은 프레임을 생성하고 더 빠르게 움직입니다 (골프 버전에서는 숫자를 변경하여 조정할 수 있음).

시료:

f(11,5,90,2,99,0) 프로그램 종료 후

골프 샘플

epic(1.3,4,2,6,6,1) gif 출력

ungolfed 샘플

Ungolfed 코드

%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

골프 코드

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

명령:

같은 이름의 파일에 함수를 저장하십시오 (예 : epic.m또는) f.m. Matlab 콘솔에서 함수를 호출하여 실행하십시오.

사용법 : epic(r, r1, r2, n1, n2, dispPoly) 여기서 dispPoly폴리곤을 그릴 지 여부를 결정하는 부울 변수 (거짓이면 0, 참이면 0이 아닌 숫자)입니다.

편집 : 애니메이션 이미지에 50의 보너스가 추가되었습니다.


14

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

3800 ish 바이트에서 개선

귀하의 제안 (특히 pseudonym117)에 감사드립니다. 새로운 버전이 있습니다.

포인트 클래스 인 클래스 P와 ArrayList를 확장하는 클래스 L을 추가했습니다.

또한 약간의 논리 변경 사항을 추가했습니다.

다음은 메인 클래스입니다 (골프 아님).

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

그리고 골프 버전 :

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

클래스 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;}}

그리고 나:

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

int d를 0 또는 1로 변경하여 다각형을 표시하십시오.

인수-1100 50 5 2

여기에 이미지 설명을 입력하십시오

인수-1.5100100 7 3

여기에 이미지 설명을 입력하십시오

인수-2 4010037

여기에 이미지 설명을 입력하십시오


r정말 모든 예에서 50? 이것은 롤러가 약 50 번 간다는 것을 의미합니다.
Calvin 's Hobbies

@ Calvin'sHobbies 새로운 예는 pi * 3을 보여줍니다
Stretch Maniac

1
@StretchManiac 맞지 않아요. 3π는 고정 다각형 주위에서 9 배 이상 조금씩 이동해야합니다.
Martin Ender

4
클래스 이름이 RotatingPolygonsGolfed"golfed"코드 RotatingPolygons에 있고 정상 코드에있는 방법은 재미 있습니다. ;)
Calvin 's Hobbies

1
특정 클래스 대신 *를 사용하도록 가져 오기를 변경하여 좋은 문자를 절약 할 수 있습니다.
pseudonym117

12

자바 스크립트, 1284 자 (-200 = 1084 자)

축소 된 코드는

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

전체 코드는

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

모든 다각형의 영광에서 일상을 바라보고 애니메이션을 보여주는 바이올린은

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

이 스크립트는 epiOP에 나열된 다섯 개의 매개 변수를 승인 하는 함수를 정의합니다 . 인수를 허용 epi하는 서명 (e,t,isCCW,flags)이 있는 함수를 반환합니다 .

  • e -렌더링 할 600x600 HTML5 캔버스 요소에 대한 참조
  • t-두 번째 다각형의 중심이 첫 번째 중심을 중심으로 스윕해야하는 총 각도 (라디안)입니다. 전달 된 인수는 전달 된 로테이션 수의 2 배를 초과하지 않아야합니다 epi.
  • isCCW -트레이스가 반 시계 방향으로 진행해야하는지 여부를 나타내는 부울 (시계 방향이 아닌)
  • flags -렌더링 할 요소를 나타내는 비트 플래그 세트
    • 비트 1-설정된 경우 다각형 1을 렌더링
    • 비트 2-설정된 경우 추적 렌더링
    • 비트 3-설정된 경우 다각형 2를 렌더링

이 함수는 다양한 인수 집합을 사용하여 여러 번 호출 할 수 있습니다.

일부 참고 사항 :

  • 이 루틴은 n1 = 2및 / 또는 어디에서나 퇴화 사례를 처리합니다 n2 = 2. 애니메이션을 만들 때 특정 길이의 조합을 사용하면 트레이스가 갑자기 급격히 향상됩니다. 이는 애니메이션 프레임이 두 번째 다각형의 중심에 대한 각도로 색인화되고 양면 poly 2의 중심이 양면 poly 1의 꼭짓점 근처에있는 경우 d theta poly2 / d theta 중심이 특이하게되기 때문입니다. 그러나 이것은 추적에 영향을 미치지 않습니다.

  • epi개발 전반에 걸쳐 매개 변수 이름 이 혼란스러워 보일 것입니다. 다각형 1을 "2"로, 다각형 2를 "1"이라고했습니다. 코드의 모든 인덱스를 바꾸지 않고 내 규칙과 OP의 규칙 사이의 불일치를 깨달았을 때의 인수 순서를 간단히 바 꾸었습니다 epi.

  • 위의 바이올린은 jQuery를 가져 오지만 UI를 처리하는 것입니다. 이 epi함수에는 라이브러리 종속성이 없습니다.

  • 이 코드는 Y 축을 반전시켜 CCW 트레이스를 처리합니다. CCW 추적 중에 다각형 2가 Y 반전 위치에서 시작하기 때문에 이는 다소 부적합하지만, 루틴이 우아해야한다고 아무도 말하지 않았습니다. ;)



작은 불만은 추적 정점이 고정 정점에서 시작되지 않는다는 것입니다.
Calvin 's Hobbies

하아. 나는 사양에서 그것을 완전히 간과했습니다. 코드가 원래 의도하지 않았기 때문에 'Ha'라고 말하지만 추적 정점이 변경되면 즉시 시작하면 추적이 더 좋아 보일 것이라고 생각했습니다. 사양에 맞게 코드를 업데이트하고 바이올린에 대한 링크를 전체 화면 사양 호환 버전으로 업데이트했습니다. 보너스로, 총 수에서 한 캐릭터를 떨어 뜨립니다.
COTO

속도를 어떻게 높일 수 있습니까? JS 멍청한 놈.
Soham Chowdhury

@SohamChowdhury : 코드 nt = ~~(t*(r_>rC?r_:rC)+1)를 변경하면 nt = ~~(t*(r_>rC?r_:rC)/10+1)속도가 약간 빨라집니다.
COTO
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.