Малювання епіциклонів


22

Епіциклоїда є кривою точка на окружності , як це робить катається ще одне коло. Cyclogon це форма точка на правильний багатокутник робить , як вона котиться по площині. 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. (Отже, за чверть обороту лінія, що з'єднує центроїди, змітається на 90 градусів.)
  • Ці аргументи повинні надходити з командного рядка, або ваша програма повинна запросити їх (наприклад, з Python's input()).
  • r1і r2відносно один одного, а не розміри зображення. Таким чином, ви можете встановити одну "одиницю" будь-якої кількості фактичних пікселів.

Точка, яку ви повинні простежити, - одна з вершин форми кочення. Фігури повинні починатися з цієї вершини, яка торкається нерухомої вершини та двох сусідніх сторін:

приклад епіциклона

Точні початкові вершини та кут нерухомого багатокутника значення не мають.

Вихідні дані

Вихід повинен мати зображення, яке має принаймні 600x600 пікселів (або якийсь змінний розмір, ніж можна встановити на 600). Він повинен показувати всю криву епіциклона, задану параметрами, добре обрамлену на зображенні.

Полігони, що котяться і нерухомі, також повинні бути намальовані (з роликом у остаточному стані). Дві форми і епіциклон мають бути трьома помітно різними кольорами.

Там також повинен бути простий спосіб НЕ малювати багатокутники (зміна trueна falseв коді вистачає).

Будь ласка, покажіть нам щонайменше 2 вихідних зображення. Це нормально, якщо потрібно, щоб зменшити їх.

Оцінка балів

Виграє найкоротший код, який створює дійсні вихідні зображення.

Бонуси

  • Мінус 50 байт, якщо висновок є анімований gif (або подібний) кривої, що малюється.
  • Мінус 150 байт, якщо ви дозволите n1і n2приймаєте значення 2, тому фігури стають лінійними відрізками довжини 2 * r1(або r2), "котячись" навколо один одного. Як ви справляєтеся , rколи n1і n2є 2 до вас , так як центр ваги не обертається навколо один одного так , як вони роблять в інших випадках. (Якщо "кочення" взагалі не вважається обробкою.)

Оскільки я дуже нетерплячий, щоб ця романна ідея була добре виконана (і це не зовсім торт), я збираюся нагородити переможця в 150 нагород . Конкурс закінчиться того ж дня, коли виграє щедрот.

Виграш не буде присуджений переможцю, якщо зрозуміло, що вони просто переписали більшість коду з іншого подання.

Функції бібліотеки, які вже трапляються для цього (якщо такі є), заборонені.

Примітка. Це виникло з моїх запитань про залишки, які кожен може вільно публікувати. Але якщо ніхто більше не опублікує їх, є хороший шанс, що я встигну. : P


Я думаю, що проти годинникової стрілки замість цього має бути позитивним.
Soham Chowdhury

3
@SohamChowdhury Я думаю, що це навряд чи має значення.
Захоплення Кальвіна

Ти маєш рацію. Чи є у вас приклади зображень? У мене немає CDF-програвача.
Soham Chowdhury

@githubphagocyte Я бачу вашу думку. Виправлено.
Захоплення Кальвіна

@ MartinBüttner Не надто суворий, це було лише перше, що я хотів. При необхідності можна запросити значення іншим способом.
Захоплення Кальвіна

Відповіді:


3

MATLAB: 735 байт - 200 бонусів = 535

Моя програма обробляє корпус n = 2 і малює анімацію в реальному часі. Існує кілька відмінностей між версіями для гольфу та без вогню:

У версії, яка не перебуває у вільготі, є лише можливість зберегти анімацію у файл 'g.gif', встановивши savegif = 1в коді. Він вимкнений за замовчуванням, оскільки може дратувати з кількох причин:

  • Створення небажаного файлу
  • Можливе відставання
  • Помилка генерується, якщо у вас є кілька моніторів, і вікно сюжету знаходиться не з правого… Збереження gif потрібно було скинути в гольф-версії, оскільки воно займало близько 100 байт, що перевищує розмір бонусу.

Негольдована версія малює коло на вершині сліду. Він також створює більше кадрів і рухається швидше (хоча це можна змінити у версії для гольфу, змінивши номери).

Зразки:

f(11,5,90,2,99,0) після закінчення програми

зразок для гольфу

epic(1.3,4,2,6,6,1) з gif-виходом

зразка без вогонь

Невикористаний код

%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є булева змінна (нуль, якщо помилкова, ненульове число, якщо істина), що визначає, чи потрібно малювати багатокутники.

Редагувати: Додано бонус у розмірі 50 за анімоване зображення.


14

Ява - 2726 2634 - 200 = 2434 символи

Покращено з 3800 байт

Дякую всім за ваші пропозиції (особливо псевдонім117), ось нова версія.

Я додав клас P, який є точковим класом, і клас L, який розширює ArrayList

Я також додав деякі незначні логічні зміни.

Ось основний клас (не гольф):

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

І L:

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, щоб показати багатокутники

аргументи - 1 100 50 5 2

введіть тут опис зображення

арги - 1,5 100 100 7 3

введіть тут опис зображення

арги - 2 40 100 3 7

введіть тут опис зображення


Чи rсправді 50 у всіх ваших прикладах? Це означало б, що ролик йде приблизно в 50 разів.
Захоплення Кальвіна

Новий приклад @ Calvin'sHobbies показує pi * 3
Stretch Maniac

1
@StretchManiac Це не може бути правильним. 3π повинен пройти трохи більше 9 разів навколо нерухомого багатокутника.
Мартін Ендер

4
Смішно, як назва класу RotatingPolygonsGolfedв коді "гольф", тоді як це просто RotatingPolygonsу звичайному коді. ;)
Захоплення Кальвіна

1
ви можете зберегти гарний шматок символів, просто змінивши імпорт, щоб використовувати * замість конкретних класів ...
pseudonym117

12

Javascript, 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/

Сценарій визначає функцію, яка називається, epiяка приймає п'ять перерахованих параметрів в ОП. epiповертає функцію з підписом, (e,t,isCCW,flags)яка приймає аргументи:

  • e - посилання на елемент полотна HTML5 600x600, на якому потрібно відобразити
  • t- загальний кут (у радіанах), який має бути центроїдом другого багатокутника, прокотитися навколо центроїда першого. Переданий аргумент не повинен перевищувати 2 пі разів більше кількості переданих обертань epi.
  • isCCW - булеве, що вказує, чи слід слід в напрямку проти годинникової стрілки (на відміну від годинникової стрілки)
  • flags - набір бітових прапорів із зазначенням, які елементи слід винести
    • біт 1 - візуалізуйте багатокутник 1, якщо його встановлено
    • біт 2 - візуалізація сліду, якщо вона встановлена
    • біт 3 - візуалізуйте багатокутник 2, якщо його встановлено

Функцію можна викликати будь-яку кількість разів з різними наборами аргументів.

Деякі примітки:

  • Звичайний порядок обробляє вироджені випадки, коли n1 = 2та / або n2 = 2. Під час анімації певні поєднання довжин можуть викликати раптові швидкі просування сліду. Це відбувається тому, що анімаційні кадри індексуються кутом до центроїда другого многокутника, а d theta poly2 / d тета центроїд стає сингулярним у випадках, коли центроїд двостороннього полі 2 знаходиться поблизу вершини двостороннього полі 1 Однак це не впливає на слід.

  • Імена параметрів у epiздадуться заплутаними, оскільки впродовж усієї розробки я називав багатокутник 1 "2", а полігон 2 - "1". Коли я зрозумів невідповідність між моєю конвенцією та ОП, замість того, щоб заміняти всі індекси в коді, я просто змінив порядок аргументів на epi.

  • Загадка вище імпортує jQuery, але це для обробки інтерфейсу користувача. epiФункція не має бібліотечних залежностей.

  • Код обробляє сліди CCW, просто перевернувши вісь Y. Це дещо неелегантно, оскільки багатокутник 2 починається в перевернутому Y місці під час слідів CCW, але ніхто не сказав, що рутина повинна бути елегантною. ;)


1
Гарний! Я знайшов посилання на повноекранному екрані, з яким найпростіше працювати: jsfiddle.net/7rv751jy/embedded/result
Захоплення Кальвіна

Одна крихітна скарга - це те, що вершина сліду не починається на нерухому вершину.
Захоплення Кальвіна

Ха. Я це зовсім не помітив у специфікаціях. Я кажу "Ха", тому що код був спочатку (ненавмисно) специфічним, але я змінив вершину сліду, тому що вважав, що слід буде виглядати краще, якщо він розпочнеться негайно. Я оновив код так, щоб він був специфічним, і оновив посилання на скрипку до повноекранної версії, сумісної з специфікаціями. Як бонус, він збиває одного персонажа із загальної кількості.
COTO

Як я можу це трохи пришвидшити? JS noob тут.
Soham Chowdhury

@SohamChowdhury: Змінити код , nt = ~~(t*(r_>rC?r_:rC)+1)щоб nt = ~~(t*(r_>rC?r_:rC)/10+1)і він повинен прискорити процес небагато.
COTO
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.