Sprocket साइंस: एक चेन ड्राइव सिस्टम को एनिमेटेड करना


96

इस चुनौती का लक्ष्य एक चेन ड्राइव सिस्टम का एक एनीमेशन तैयार करना है, जिसमें एक चेन द्वारा जुड़े स्प्रोकेट गियर के एक सेट से मिलकर बना है।

सामान्य आवश्यकताएँ

आपके कार्यक्रम को sprockets की एक सूची दी जाएगी , जिसे (x, y, radius)ट्रिपल के रूप में निर्दिष्ट किया गया है । जिसके परिणामस्वरूप श्रृंखला ड्राइव प्रणाली इन sprockets, एक से एक साथ जुड़े के शामिल है बंद तना हुआ श्रृंखला उनमें से प्रत्येक के ऊपर से गुजर, क्रम में । आपका लक्ष्य एक असीम लूपिंग एनीमेशन का उत्पादन करना है , जो सिस्टम को गति में दिखाता है। उदाहरण के लिए, इनपुट दिया गया

(0, 0, 16),  (100, 0, 16),  (100, 100, 12),  (50, 50, 24),  (0, 100, 12)

आउटपुट कुछ इस तरह दिखना चाहिए

उदाहरण 1

समन्वय प्रणाली इस तरह के एक्स-अक्ष सही अंक, और y- अक्ष अंक ऊपर है कि होना चाहिए। आप मान सकते हैं कि त्रिज्या संख्या 8 से अधिक या उसके बराबर है (हम देखेंगे कि यह बाद में क्यों मायने रखता है।) आप यह भी मान सकते हैं कि कम से कम दो sprockets हैं , और यह है कि sprockets एक दूसरे को नहीं काटते हैंइकाइयोंइनपुट बहुत क्रिटिकल नहीं हैं। इस पोस्ट में सभी उदाहरण और परीक्षण मामले इनपुट इकाइयों के रूप में पिक्सल का उपयोग करते हैं (इसलिए, उदाहरण के लिए, पिछले आंकड़े में मध्य sprocket की त्रिज्या 24 पिक्सेल है;) इन इकाइयों से बहुत अधिक विचलन न करने का प्रयास करें। शेष चुनौती में, स्थानिक मात्राओं को उसी इकाइयों में दिया जाना समझा जाता है, जैसा कि अनुपात को सही रखने के लिए सुनिश्चित करें! उत्पादन के आयामसभी sprockets के बाउंडिंग बॉक्स से थोड़ा बड़ा होना चाहिए, इतना बड़ा कि पूरा सिस्टम दिखाई दे। विशेष रूप से, स्प्रोकेट के पूर्ण स्थान को आउटपुट को प्रभावित नहीं करना चाहिए; केवल उनके सापेक्ष पदों को (इसलिए, उदाहरण के लिए, यदि हमने उपरोक्त उदाहरण में सभी राशि को समान मात्रा में स्थानांतरित किया, तो आउटपुट समान रहेगा।)

श्रृंखला को स्पॉकेट्स के साथ स्पर्श किया जाना चाहिए जो संपर्क के सभी बिंदुओं पर गुजरता है, और सीधे हर जगह। श्रृंखला को sprockets के ऊपर से गुजरना चाहिए जैसे कि आसन्न श्रृंखला खंड (यानी, दो sprockets के बीच श्रृंखला के भाग, जो एक ही sprocket पर मिलते हैं) एक दूसरे को नहीं काटते हैं।

चेन इंटरसेक्शन

उदाहरण के लिए, जबकि ऊपर की बाईं प्रणाली वैध है, मध्य एक नहीं है, क्योंकि दो आसन्न श्रृंखला खंड जो नीचे बाएं स्प्रोकेट चौराहे से गुजरते हैं। हालांकि, ध्यान दें कि सही प्रणाली है मान्य है, क्योंकि दो अन्तर्विभाजक श्रृंखला क्षेत्रों आसन्न नहीं हैं (इस प्रणाली हालांकि, के अलावा अन्य दो एक अलग इनपुट द्वारा निर्मित है।)

चीजों को सरल (r) रखने के लिए, आप मान सकते हैं कि कोई भी sprocket अपने दो पड़ोसी sprockets के उत्तल पतवार , या उसके प्रत्येक पड़ोसी और उनके दूसरे पड़ोसी के उत्तल पतवार को नहीं काटता है। दूसरे शब्दों में, नीचे दिए गए आरेख में शीर्ष स्थान किसी भी छायांकित क्षेत्र को नहीं काट सकता है।

बहिष्करण

चेन सेगमेंट, उनके ऊपर से गुजरने वाले स्पैक्ट्रेट्स को पार कर सकते हैं (जैसे कि अंतिम टेस्ट केस में)। इस मामले में, श्रृंखला हमेशा sprockets के सामने दिखाई देनी चाहिए।

दृश्य आवश्यकताएँ

श्रृंखला में वैकल्पिक चौड़ाई के लिंक की एक श्रृंखला शामिल होनी चाहिए । संकीर्ण लिंक की चौड़ाई लगभग 2 होनी चाहिए, और चौड़ी लिंक की चौड़ाई लगभग 5. होनी चाहिए। दोनों प्रकार के लिंक की लंबाई लगभग बराबर होनी चाहिए। अवधिश्रृंखला की, यानी, लिंक की एक विस्तृत / संकीर्ण जोड़ी की कुल लंबाई, 4π के निकटतम संख्या होनी चाहिए जो श्रृंखला की लंबाई में एक पूर्णांक संख्या को फिट करती है। उदाहरण के लिए, यदि श्रृंखला की लंबाई 1,000 है, तो इसकी अवधि 12.5 होनी चाहिए, जो कि 466 (12.566 ...) के निकटतम संख्या है जो 1,000 में एक पूर्णांक संख्या (80) को फिट करती है। श्रृंखला की लंबाई में एक पूर्णांक संख्या को फिट करने की अवधि के लिए यह महत्वपूर्ण है, ताकि उस बिंदु पर कोई कलाकृतियां न हों जहां श्रृंखला चारों ओर घूमती है।

जंजीर


त्रिज्या आर का एक स्प्रोकेट तीन गाढ़ा भागों से मिलकर होना चाहिए: एक केंद्रीय धुरा , जो त्रिज्या का एक चक्र होना चाहिए 3 के बारे में; स्प्रोकेट के शरीर , धुरा, जिसके बारे में त्रिज्या का एक चक्र होना चाहिए चारों ओर आर - 4.5; और स्प्रोकेट का रिम , शरीर के चारों ओर, जो कि
आर - 1.5 के बारे में त्रिज्या का एक चक्र होना चाहिए । रिम में sprocket के दांत भी होने चाहिए , जिसकी चौड़ाई लगभग 4 होनी चाहिए; दांतों के आकार और रिक्ति को चेन लिंक के आकार से मेल खाना चाहिए, ताकि वे बड़े करीने से घेरे रहें।

स्प्रोकेट

Sprocket के दांतों की अवधि, यानी, sprocket की परिधि के साथ लगातार दो दांतों के बीच की दूरी, श्रृंखला की अवधि से मेल खाना चाहिए। चूंकि अवधि लगभग 4π है, और चूंकि स्प्रोकेट की त्रिज्या की गारंटी दी जाती है, यहां तक ​​कि अवधि को स्प्रोकेट की परिधि में लगभग एक-पूर्णांक संख्या में फिट होना चाहिए, ताकि बिंदु पर कोई ध्यान देने योग्य कलाकृतियां न हों। Sprocket के दाँत चारों ओर लपेटते हैं।

आप श्रृंखला के लिए रंगों के किसी भी संयोजन का उपयोग कर सकते हैं , स्प्रोकेट के विभिन्न भागों और पृष्ठभूमि, जब तक वे आसानी से अलग-अलग होते हैं । पृष्ठभूमि पारदर्शी हो सकती है। इस पोस्ट में दिए गए उदाहरण चैन का रंग #202020चेन के लिए उपयोग करते हैं, Sprocket धुरा और रिम रंग #868481स्प्रोकेट के एक्सल और रिम के स्प्रोकेट बॉडी कलर #646361लिए और स्प्रोकेट के शरीर के लिए।

एनिमेशन आवश्यकताएँ

पहले स्प्रोकेट इनपुट सूची बारी बारी चाहिए में दक्षिणावर्त ; बाकी sprockets को उसी के अनुसार घूमना चाहिए। श्रृंखला को प्रति सेकंड 16 a (लगभग 50) इकाइयों की गति से बढ़ना चाहिए ; फ़्रेम दर आपके ऊपर है, लेकिन एनीमेशन को पर्याप्त रूप से चिकना होना चाहिए।

एनीमेशन को मूल रूप से लूप करना चाहिए ।

अनुरूपता

दृश्य विशेषताओं और अनुपातों में से कुछ जानबूझकर केवल मोटे तौर पर निर्दिष्ट किए जाते हैं - आपको उनसे बिल्कुल मेल नहीं खाना है । आपके प्रोग्राम के आउटपुट को यहां दिए गए उदाहरणों का पिक्सेल-टू-पिक्सेल प्रतिकृति नहीं होना चाहिए, लेकिन यह समान दिखना चाहिए। विशेष रूप से, श्रृंखला और sprockets के सटीक अनुपात, और श्रृंखला के लिंक और sprocket के दांतों का सटीक आकार, लचीले होते हैं।

पालन ​​करने के लिए सबसे महत्वपूर्ण बिंदु ये हैं:

  • श्रृंखला को सही दिशा से, इनपुट क्रम में, sprockets के ऊपर से गुजरना चाहिए।
  • श्रृंखला को संपर्क के सभी बिंदुओं पर स्पॉकेट्स के लिए स्पर्शरेखा होना चाहिए।
  • श्रृंखला और sprockets के दांतों के लिंक को बड़े करीने से कम से कम सही स्थान और चरण तक घेरना चाहिए।
  • श्रृंखला के लिंक, और sprockets के दांतों के बीच अंतर, ऐसा होना चाहिए कि उस बिंदु पर ध्यान देने योग्य कलाकृतियां नहीं हैं जहां वे चारों ओर लपेटते हैं।
  • Sprockets को सही दिशा में घुमाना चाहिए।
  • एनीमेशन को मूल रूप से लूप करना चाहिए।

अंतिम नोट के रूप में, जबकि, तकनीकी रूप से, इस चुनौती का लक्ष्य सबसे छोटा कोड लिखना है, अगर आपको लगता है कि रचनात्मक हो रहा है और सभी तरीकों से अधिक विस्तृत आउटपुट का उत्पादन कर रहा है, तो इसके लिए जाएं!

चुनौती

जैसा कि ऊपर वर्णित है, एक कार्यक्रम या एक समारोह लिखें , sprockets की एक सूची ले रहा है, और इसी श्रृंखला ड्राइव सिस्टम एनीमेशन का निर्माण कर रहा है।

इनपुट और आउटपुट

आप समय लग सकता है इनपुट के माध्यम से कमांड लाइन , के माध्यम से STDIN , के रूप में समारोह तर्क है, या एक का उपयोग कर बराबर विधि । आप इनपुट के लिए किसी भी सुविधाजनक प्रारूप का उपयोग कर सकते हैं , लेकिन इसे अपनी पोस्ट में निर्दिष्ट करना सुनिश्चित करें।

आउटपुट के रूप में , आप सीधे एनीमेशन प्रदर्शित कर सकते हैं , एक एनीमेशन फ़ाइल (जैसे, एक एनिमेटेड GIF) का उत्पादन कर सकते हैं, या फ़्रेम फ़ाइलों के अनुक्रम का उत्पादन कर सकते हैं (हालांकि, इस मामले में एक छोटा जुर्माना है; नीचे देखें।) यदि आप फ़ाइल आउटपुट का उपयोग करते हैं, सुनिश्चित करें कि फ़्रेमों की संख्या उचित है (इस पोस्ट में उदाहरण बहुत कम फ़्रेमों का उपयोग करते हैं;) फ़्रेमों की संख्या न्यूनतम नहीं होनी चाहिए, लेकिन आपको बहुत अधिक फ़ालतू फ़्रेमों का उत्पादन नहीं करना चाहिए। यदि आप फ़्रेम का एक अनुक्रम आउटपुट करते हैं, तो अपनी पोस्ट में फ़्रेम दर निर्दिष्ट करना सुनिश्चित करें

स्कोर

यह कोड-गोल्फ है । सबसे छोटा जवाब , बाइट्स में, जीतता है।

+ 10% पेनल्टी   यदि आपका प्रोग्राम आउटपुट के रूप में फ़्रेम का एक अनुक्रम उत्पन्न करता है, तो एनीमेशन को सीधे प्रदर्शित करने या एकल एनीमेशन फ़ाइल का उत्पादन करने के बजाय, अपने स्कोर में 10% जोड़ें।

परीक्षण के मामलों

परीक्षण 1

(0, 0, 26),  (120, 0, 26)

परीक्षण 1

परीक्षण २

(100, 100, 60),  (220, 100, 14)

परीक्षण २

परीक्षण ३

(100, 100, 16),  (100, 0, 24),  (0, 100, 24),  (0, 0, 16)

परीक्षण ३

टेस्ट 4

(0, 0, 60),  (44, 140, 16),  (-204, 140, 16),  (-160, 0, 60),  (-112, 188, 12),
(-190, 300, 30),  (30, 300, 30),  (-48, 188, 12)

टेस्ट 4

परीक्षण ५

(0, 128, 14),  (46.17, 63.55, 10),  (121.74, 39.55, 14),  (74.71, -24.28, 10),
(75.24, -103.55, 14),  (0, -78.56, 10),  (-75.24, -103.55, 14),  (-74.71, -24.28, 10),
(-121.74, 39.55, 14),  (-46.17, 63.55, 10)

परीक्षण ५

परीक्षण ६

(367, 151, 12),  (210, 75, 36),  (57, 286, 38),  (14, 181, 32),  (91, 124, 18),
(298, 366, 38),  (141, 3, 52),  (80, 179, 26),  (313, 32, 26),  (146, 280, 10),
(126, 253, 8),  (220, 184, 24),  (135, 332, 8),  (365, 296, 50),  (248, 217, 8),
(218, 392, 30)

परीक्षण ६



मज़े करो!


38
ये गिफ्स बहुत संतुष्ट हैं +1
अदनान

24
अगर कोई भी किसी भी कोड के साथ इसका सफलतापूर्वक जवाब देता है तो मैं प्रभावित होऊंगा।
डेविड नोव

5
आपने जिफ कैसे बनाया? और यह कब तक काम करता है?
जे Atkin

10
@JAtkin उसी तरह से हर किसी को होना चाहिए: मैंने एक समाधान लिखा :) अगर आप बारीकियों के बारे में पूछ रहे हैं, तो मैंने काइरो का उपयोग व्यक्तिगत फ्रेम के लिए किया है, और फिर इमेजिमगिक का इस्तेमाल जिफ बनाने के लिए किया है (बीटीडब्लू, अगर कोई एनीमेशन का उत्पादन करना चाहता है) जिस तरह से, पहले तख्ते को उत्पन्न करके और फिर उन्हें एनीमेशन में बदलने के लिए एक बाहरी उपकरण का उपयोग करके, मैं इसके साथ पूरी तरह से ठीक हूं , जब तक आप अपने पोस्ट में उपकरण पर निर्भरता निर्दिष्ट करते हैं। बस स्पष्ट होने के लिए, यह आपका है। कार्यक्रम है कि उपकरण को आमंत्रित करना चाहिए, न कि उपयोगकर्ता।)
एल '

5
@Anko अच्छी खबर यह है कि आपको इसके बारे में चिंता करने की ज़रूरत नहीं है: यह स्थिति इनपुट में नहीं होने की गारंटी है; "नहीं sprocket उत्तल पतवार को देखता है ..." भाग, तीन छायांकित क्षेत्रों के साथ छवि वाला। अधिक आम तौर पर, श्रृंखला केवल एक बार ही पार कर जाती है, जो कि sprockets के आदेश के अनुसार होती है, भले ही ऐसा लगता है कि यह एक से अधिक बार एक sprocket के पास से गुजरता है।
एल

जवाबों:


42

जावास्क्रिप्ट (ईएस 6), 2557 1915 1897 1681 बाइट्स

यह वास्तव में सुपर- डुपर गोल्फ नहीं है; यह छोटा है - आंशिक रूप से हाथ से - लेकिन यह कुछ खास नहीं है। अगर मैं इसे छोटा करने से पहले इसे और अधिक घेर लूंगा, तो इसमें कोई शक नहीं रह सकता है, लेकिन मैंने पहले ही इस पर पर्याप्त समय खर्च कर दिया है।

संपादित करें: ठीक है, इसलिए मैंने इस पर अधिक समय बिताया और कोड करने से पहले कोड को और अधिक गोल्फ किया (बहुत ही मैन्युअल रूप से इस बार)। कोड अभी भी उसी दृष्टिकोण और समग्र संरचना का उपयोग कर रहा है, लेकिन फिर भी मैं अभी भी 642 बाइट्स बचा रहा हूं। बहुत जर्जर नहीं, अगर मैं खुद ऐसा कहूं। शायद कुछ बाइट-सेविंग के मौके चूक गए, लेकिन इस समय भी मुझे यकीन नहीं है कि यह अब कैसे काम करता है। केवल एक चीज जो आउटपुट के मामले में अलग है, वह यह है कि अब यह थोड़ा अलग रंगों का उपयोग करता है जो कि और अधिक लिखे जा सकते हैं।

2 संपादित करें (बहुत बाद में): 18 बाइट्स सहेजे गए। टिप्पणी में ConorO'Brien के लिए धन्यवाद स्पष्ट रूप से स्पष्ट है कि मैं पूरी तरह से याद किया था इंगित करने के लिए।

संपादित करें 3: तो, मुझे लगा कि मैं अपना खुद का कोड रिवर्स इंजीनियर करूंगा, क्योंकि, स्पष्ट रूप से, मुझे याद नहीं है कि मैंने इसे कैसे किया है, और मैं अनफॉर्म्ड संस्करणों को खो देता हूं। तो मैं गुजर गया, और लो और निहारना एक और 316 बाइट्स को पुनर्गठन और कुछ माइक्रो-गोल्फिंग द्वारा बचाने के लिए मिला।

R=g=>{with(Math){V=(x,y,o)=>o={x,y,l:sqrt(x*x+y*y),a:v=>V(x+v.x,y+v.y),s:v=>o.a(v.m(-1)),m:f=>V(x*f,y*f),t:r=>V(x*cos(r)-y*sin(r),x*sin(r)+y*cos(r)),c:v=>x*v.y-y*v.x,toString:_=>x+','+y};a='appendChild',b='setAttribute';S=(e,a)=>Object.keys(a).map(n=>e[b](n,a[n]))&&e;T=(t,a)=>S(k.createElementNS('http://www.w3.org/2000/svg',t),a);C=(e,a)=>S(e.cloneNode(),a);P=a=>T('path',(a.fill='none',a));w=h=-(x=y=1/0);G=g.map((a,g)=>(g=V(...a))&&(u=(g.r=a[2])+5,x=min(x,g.x-u),y=min(y,g.y-u),w=max(w,g.x+u),h=max(h,g.y+u))&&g);k=document;I=k[a].bind(k.body[a](T('svg',{width:w-x,height:h-y}))[a](T('g',{transform:`translate(${-x},${h})scale(1,-1)`})));L=(c)=>(h=G.length)&&G.map((g,i)=>c(G[i],G[i?i-1:h-1],G[(i+1)%h]))&&L;l='';L((g,p,n)=>g.f=p.s(g).c(n.s(g))>0)((g,a,n)=>{d=g.s(n),y=x=1/d.l;g.f!=n.f?(a=asin((g.r+n.r)*x),g.f?(x=-x,a=-a):(y=-y)):(a=asin((g.r-n.r)*x),g.f&&(x=y=-x,a=-a));t=d.t(a+PI/2);g.o=t.m(x*g.r).a(g);n.i=t.m(y*n.r).a(n)})((g,p,n)=>{z='#888';d=(l,s,e)=>`A${g.r},${g.r} 0 ${1*l},${1*s} ${e}`;e=(f,r)=>T('circle',{cx:g.x,cy:g.y,r,fill:f});g.k=p.o.s(n.i).l<g.i.s(g.o).l;w=d(g.k,!g.f,g.o);g.j=`${w}L${n.i}`;l+=g.j;I(e(z,g.r-1.5));g.g=I(P({d:`M${g.i}${w}${d(!g.k,!g.f,g.i)}`,stroke:z,'stroke-width':5}));g.h=I(C(g.g,{d:`M${g.i}${g.j}`,stroke:'#222'}));I(e('#666',g.r-4.5));I(e(z,3))});t=e=>e.getTotalLength(),u='stroke-dasharray',v='stroke-dashoffset',f=G[0];l=I(C(f.h,{d:'M'+f.i+l,'stroke-width':2}));s=f.w=t(l)/round(t(l)/(4*PI))/2;X=8*s;Y=f.v=0;L((g,p)=>{g.g[b](u,s);g.h[b](u,s);g==f||(g.w=p.w+t(p.h),g.v=p.v+t(p.h));g.g[b](v,g.w);g.h[b](v,g.v);g.h[a](C(g.g[a](T('animate',{attributeName:v,from:g.w+X,to:g.w+Y,repeatCount:'indefinite',dur:'1s'})),{from:g.v+X,to:g.v+Y}))})}}

उपरोक्त फ़ंक्शन दस्तावेज़ में एक एसवीजी तत्व (एनिमेशन सहित) जोड़ता है। 2 के परीक्षण के मामले को प्रदर्शित करने के लिए जैसे:

R([[100, 100, 60],  [220, 100, 14]]);

कम से कम क्रोम में एक ट्रीट काम करने के लिए लगता है।

नीचे दिए गए स्निपेट में इसे आज़माएं (बटन पर क्लिक करने से ओपी के प्रत्येक परीक्षण के मामले आकर्षित होंगे)।

कोड एक धराशायी स्ट्रोक के रूप में श्रृंखला और गियर के दांतों को खींचता है। यह तब गुण animateको चेतन करने के लिए तत्वों का उपयोग करता है stroke-dashoffset। परिणामी एसवीजी तत्व आत्म-निहित है; कोई जेएस-चालित एनीमेशन या सीएसएस स्टाइल नहीं है।

चीजों को अच्छी तरह से रेखा बनाने के लिए, प्रत्येक गियर के दांतों की अंगूठी वास्तव में दो आर्क्स से युक्त पथ के रूप में खींची जाती है, इसलिए पथ स्पर्शरेखा बिंदु पर सही शुरू हो सकता है जहां श्रृंखला स्पर्श करती है। यह इसे लाइन अप करने के लिए बहुत सरल बनाता है।

इसके अलावा, ऐसा लगता है कि एसवीजी के धराशायी स्ट्रोक का उपयोग करते समय बहुत सारी गोल त्रुटियां हैं। कम से कम, कि मैंने क्या देखा; लंबे समय तक श्रृंखला, प्रत्येक क्रमिक गियर के साथ यह खराब होगा। इसलिए समस्या को कम करने के लिए, श्रृंखला वास्तव में कई रास्तों से बनी है। प्रत्येक पथ में एक गियर के आसपास एक arcing खंड होता है और अगले गियर के लिए एक सीधी रेखा होती है। उनके डैश-ऑफ़सेट का मिलान करने के लिए गणना की जाती है। श्रृंखला का पतला "आंतरिक" हिस्सा, हालांकि, यह केवल एक लूपिंग पथ है, क्योंकि यह एनिमेटेड नहीं है।


2
अच्छा लग रहा है! एक पुरानी (ईश) चुनौती का जवाब देने के लिए यश!
एल

1
-2 बाइट्स:R=g=>...
कॉनर ओ'ब्रायन

1
@ फेलम्बिनो, मुझे इस चुनौती के लिए आपका समाधान पसंद है और मुझे वास्तव में खेद है कि आपने मूल स्रोत खो दिया, मैंने इसे ठीक करने के लिए कुछ उलटफेर किए, यह यहां पाया जा सकता है: gist.github.com/micnic/6aec0dd6332022aa778c6775ec7f9aa मैं भी इसकी पुष्टि करता हूं। मैन्युअल रूप से 1665 बाइट्स के लिए (इसे और भी छोटा किया जा सकता है, लेकिन मैं आज आलसी हूं)
12

1
@ जातीय धन्यवाद! मुझे यह देखना होगा! और चिंता न करें, मैं इसे भी रिवर्स करने में कामयाब रहा, इसलिए मेरे पास अधिक पठनीय संस्करण है। लेकिन, खतरे, 16 बाइट्स कम? कुडोस! मैं निश्चित रूप से इसे एक रूप दे दूंगा जब मुझे समय मिल सकता है
फ्लैम्बिनो

1
@Flambino, अनिवार्य रूप से फ़ाइल आकार पर सबसे बड़ा प्रभाव svg संरचना था, मैंने evething को एक में नहीं रखा <g>, लेकिन इसे सीधे svg रूट में डाल दिया। एक ऐसी जगह भी मिली जहाँ आपने झाड़ू और बड़े चाप के झंडे को बूलियन से नंबर इस्तेमाल करने के लिए बदल दिया 1*x, लेकिन आप इस्तेमाल कर सकते हैं+x
micnic

40

सी # 3566 बाइट्स

सब पर गोल्फ नहीं है, लेकिन काम करता है (मुझे लगता है)

संपादित इतिहास में अनप्लग्ड।

Gif रेंडर करने के लिए Magick.NET का उपयोग करता है।

class S{public float x,y,r;public bool c;public double i,o,a=0,l=0;public S(float X,float Y,float R){x=X;y=Y;r=R;}}class P{List<S>q=new List<S>();float x=float.MaxValue,X=float.MinValue,y=float.MaxValue,Y=float.MinValue,z=0,Z=0,N;int w=0,h=0;Color c=Color.FromArgb(32,32,32);Pen p,o;Brush b,n,m;List<PointF>C;double l;void F(float[][]s){p=new Pen(c,2);o=new Pen(c,5);b=new SolidBrush(c);n=new SolidBrush(Color.FromArgb(134,132,129));m=new SolidBrush(Color.FromArgb(100,99,97));for(int i=0;i<s.Length;i++){float[]S=s[i];q.Add(new S(S[0],S[1],S[2]));if(S[0]-S[2]<x)x=S[0]-S[2];if(S[1]-S[2]<y)y=S[1]-S[2];if(S[0]+S[2]>X)X=S[0]+S[2];if(S[1]+S[2]>Y)Y=S[1]+S[2];}q[0].c=true;z=-x+16;Z=-y+16;w=(int)(X-x+32);h=(int)(Y-y+32);for(int i=0;i<=q.Count;i++)H(q[i%q.Count],q[(i+1)%q.Count],q[(i+2)%q.Count]);C=new List<PointF>();for(int i=0;i<q.Count;i++){S g=q[i],k=q[(i+1)%q.Count];if(g.c)for(double a=g.i;a<g.i+D(g.o,g.i);a+=Math.PI/(2*g.r)){C.Add(new PointF((float)(g.x+z+g.r*Math.Cos(a)),(float)(g.y+Z+g.r*Math.Sin(a))));}else
for(double a=g.o+D(g.i,g.o);a>g.o;a-=Math.PI/(2*g.r)){C.Add(new PointF((float)(g.x+z+g.r*Math.Cos(a)),(float)(g.y+Z+g.r*Math.Sin(a))));}C.Add(new PointF((float)(g.x+z+g.r*Math.Cos(g.o)),(float)(g.y+Z+g.r*Math.Sin(g.o))));C.Add(new PointF((float)(k.x+z+k.r*Math.Cos(k.i)),(float)(k.y+Z+k.r*Math.Sin(k.i))));k.l=E(C);}l=E(C);N=(float)(K(l)/10.0);o.DashPattern=new float[]{N,N};double u=q[0].i;for(int i=0;i<q.Count;i++){S g=q[i];double L=g.l/(N*5);g.a=g.i+((1-(L%2))/g.r*Math.PI*2)*(g.c?1:-1);}List<MagickImage>I=new List<MagickImage>();for(int i=0;i<t;i++){using(Bitmap B=new Bitmap(w,h)){using(Graphics g=Graphics.FromImage(B)){g.Clear(Color.White);g.SmoothingMode=System.Drawing.Drawing2D.SmoothingMode.AntiAlias;foreach(S U in q){float R=U.x+z,L=U.y+Z,d=7+2*U.r;PointF[]f=new PointF[4];for(double a=(i*(4.0/t));a<2*U.r;a+=4){double v=U.a+((U.c?-a:a)/U.r*Math.PI),j=Math.PI/U.r*(U.c?1:-1),V=v+j,W=V+j,r=U.r+3.5;f[0]=new PointF(R,L);f[1]=new PointF(R+(float)(r*Math.Cos(v)),L+(float)(r*Math.Sin(v)));f[2]=new PointF(R+(float)(r*Math.Cos(V)),L+(float)(r*Math.Sin(V)));f[3]=new PointF(R+(float)(r*Math.Cos(W)),L+(float)(r*Math.Sin(W)));g.FillPolygon(n,f);}d=2*(U.r-1.5f);g.FillEllipse(n,R-d/2,L-d/2,d,d);d=2*(U.r-4.5f);g.FillEllipse(m,R-d/2,L-d/2,d,d);d=6;g.FillEllipse(n,R-d/2,L-d/2,d,d);}g.DrawLines(p,C.ToArray());o.DashOffset=(N*2.0f/t)*i;g.DrawLines(o,C.ToArray());B.RotateFlip(RotateFlipType.RotateNoneFlipY);B.Save(i+".png",ImageFormat.Png);I.Add(new MagickImage(B));}}}using(MagickImageCollection collection=new MagickImageCollection()){foreach(MagickImage i in I){i.AnimationDelay=5;collection.Add(i);}QuantizeSettings Q=new QuantizeSettings();Q.Colors=256;collection.Quantize(Q);collection.Optimize();collection.Write("1.gif");}}int t=5;double D(double a,double b){double P=Math.PI,r=a-b;while(r<0)r+=2*P;return r%(2*P);}double E(List<PointF> c){double u=0;for(int i=0;i<c.Count-1;i++){PointF s=c[i];PointF t=c[i+1];double x=s.X-t.X,y=s.Y-t.Y;u+=Math.Sqrt(x*x+y*y);}return u;}double K(double L){double P=4*Math.PI;int i=(int)(L/P);float a=(float)L/i,b=(float)L/(i+1);if(Math.Abs(P-a)<Math.Abs(P-b))return a;return b;}void H(S a,S b,S c){double A=0,r=0,d=b.x-a.x,e=b.y-a.y,f=Math.Atan2(e,d)+Math.PI/2,g=Math.Atan2(e,d)-Math.PI/2,h=Math.Atan2(-e,-d)-Math.PI/2,i=Math.Atan2(-e,-d)+Math.PI/2;double k=c.x-b.x,n=c.y-b.y,l=Math.Sqrt(d*d+e*e);A=D(Math.Atan2(n,k),Math.Atan2(-e,-d));bool x=A>Math.PI!=a.c;b.c=x!=a.c;if(a.r!=b.r)r=a.r+(x?b.r:-b.r);f-=Math.Asin(r/l);g+=Math.Asin(r/l);h+=Math.Asin(r/l);i-=Math.Asin(r/l);b.i=x==a.c?h:i;a.o=a.c?g:f;}}

क्लास पी में एक फ़ंक्शन एफ है; उदाहरण:

static void Main(string[]a){
P p=new P();
float[][]s=new float[][]{
new float[]{10,200,20},
new float[]{240,200,20},
new float[]{190,170,10},
new float[]{190,150,10},
new float[]{210,120,20},
new float[]{190,90,10},
new float[]{160,0,20},
new float[]{130,170,10},
new float[]{110,170,10},
new float[]{80,0,20},
new float[]{50,170,10}
};
p.F(s);}

यहाँ छवि विवरण दर्ज करें


2
एक गोल्फ संस्करण पोस्ट करने के लिए धन्यवाद! एक मामूली वक्रोक्ति: आपके gif में पहला स्प्रोकेट काउंटर-क्लॉकवाइज घूमता है; पहले sprocket को हमेशा दक्षिणावर्त घुमाना चाहिए।
इल

मैंने केवल सी # पास करने में देखा है, लेकिन क्या आपको publicअपनी कक्षा में प्रत्येक क्षेत्र से पहले संशोधक की आवश्यकता है ?
J Atkin

1
@Jtkin वास्तव में, वे सभी अनावश्यक हैं जहां तक ​​मैं बता सकता हूं। अन्य मामलों में, PointF वास्तव में System.Drawing.PointF है (सूची, रंग और गणित के लिए समान), इसलिए संबंधित usingखंडों को शामिल किया जाना चाहिए, या उपयोग किए जाने पर पूरी तरह से योग्य प्रकार, और System.Drawing के संदर्भ को नोट किया जाना चाहिए। जवाब में (चाहे मुझे पता नहीं स्कोर में जोड़ना चाहिए)। प्रभावशाली जवाब किसी भी तरह।
विजुअलमेल डे

@ जेटकिन मेरे पास दो वर्ग हैं, एस और पी, इसलिए एस में फ़ील्ड सभी सार्वजनिक हैं। यकीन नहीं है कि अगर उन्हें सख्त जरूरत है, लेकिन मुझे ऐसा लगता है ..
टीएफडीएल

3

जावास्क्रिप्ट (ईएस 6) 1626 बाइट्स

यह समाधान @ Flambino के समाधान के रिवर्स इंजीनियरिंग का परिणाम है, मैं इसे अपने समझौते के साथ पोस्ट करता हूं।

R=g=>{with(Math){v='stroke';j=v+'-dasharray';q=v+'-dashoffset';m='appendChild';n='getTotalLength';b='setAttribute';z='#888';k=document;V=(x,y,r,o)=>o={x,y,r,l:sqrt(x*x+y*y),a:v=>V(x+v.x,y+v.y),s:v=>o.a(v.m(-1)),m:f=>V(x*f,y*f),t:r=>V(x*cos(r)-y*sin(r),x*sin(r)+y*cos(r)),c:v=>x*v.y-y*v.x,toString:_=>x+','+y};S=(e,a)=>Object.keys(a).map(n=>e[b](n,a[n]))&&e;T=(t,a)=>S(k.createElementNS('http://www.w3.org/2000/svg',t),a);C=(e,a)=>S(e.cloneNode(),a);w=h=-(x=y=1/0);G=g.map((a,g)=>(g=V(...a))&&(u=(g.r=a[2])+5,x=min(x,g.x-u),y=min(y,g.y-u),w=max(w,g.x+u),h=max(h,g.y+u))&&g);f=G[0];w-=x;h-=y;s=T('svg',{width:w,height:h,viewBox:x+' '+y+' '+w+' '+h,transform:'scale(1,-1)'});c='';L=(c)=>(h=G.length)&&G.map((g,i)=>c(G[i],G[(h+i-1)%h],G[(i+1)%h]))&&L;L((g,p,n)=>g.w=(p.s(g).c(n.s(g))>0))((g,p,n)=>{d=g.s(n),y=x=1/d.l;g.w!=n.w?(p=asin((g.r+n.r)*x),g.w?(x=-x,p=-p):(y=-y)):(p=asin((g.r-n.r)*x),g.w&&(x=y=-x,p=-p));t=d.t(p+PI/2);g.o=t.m(x*g.r).a(g);n.i=t.m(y*n.r).a(n)})((g,p,n)=>{l=(p.o.s(n.i).l<g.i.s(g.o).l);d=(l,e)=>`A${g.r} ${g.r} 0 ${+l} ${+!g.w} ${e}`;a=d(l,g.o);e=(f,r)=>T('circle',{cx:g.x,cy:g.y,r,fill:f});c+=a+'L'+n.i;s[m](e(z,g.r-1.5));s[m](e('#666',g.r-4.5));s[m](e(z,3));g.p=s[m](C(g.e=s[m](T('path',{d:'M'+g.i+a+d(!l,g.i),fill:'none',[v]:z,[v+'-width']:5})),{d:'M'+g.i+a+'L'+n.i,[v]:'#222'}))});c=C(f.p,{d:'M'+f.i+c,[v+'-width']:2});g=c[n]();y=8*(x=g/round(g/(4*PI))/2);f.g=x;f.h=0;L((g,p)=>{g!=f&&(g.g=p.g+p.p[n](),g.h=p.h+p.p[n]());S(g.p,{[j]:x,[q]:g.h})[m](C(S(g.e,{[j]:x,[q]:g.g})[m](T('animate',{attributeName:[q],from:g.g+y,to:g.g,repeatCount:'indefinite',dur:'1s'})),{from:g.h+y,to:g.h}))});k.body[m](s)[m](c)}}

अनगोल्ड संस्करण:

class Vector {

    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.length = Math.sqrt(x * x + y * y);
    }

    add(vector) {

        return new Vector(this.x + vector.x, this.y + vector.y);
    }

    subtract(vector) {

        return new Vector(this.x - vector.x, this.y - vector.y);
    }

    multiply(scalar) {

        return new Vector(this.x * scalar, this.y * scalar);
    }

    rotate(radians) {

        const cos = Math.cos(radians);
        const sin = Math.sin(radians);

        return new Vector(this.x * cos - this.y * sin, this.x * sin + this.y * cos);
    }

    cross(vector) {

        return this.x * vector.y - this.y * vector.x;
    }

    toString() {

        return `${this.x},${this.y}`;
    }
}

class Gear {

    constructor(x, y, radius) {
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    getVector() {

        return new Vector(this.x, this.y);
    }
}

const setAttributes = (element, attributes) => {

    Object.keys(attributes).forEach((attribute) => {
        element.setAttribute(attribute, attributes[attribute]);
    });
};

const createElement = (tagName, attributes) => {

    const element = document.createElementNS('http://www.w3.org/2000/svg', tagName);

    setAttributes(element, attributes);

    return element;
};

const cloneElement = (element, attributes) => {

    const clone = element.cloneNode();

    setAttributes(clone, attributes);

    return clone;
};

const createPath = (attributes) => {

    return createElement('path', {
        ...attributes,
        fill: 'none'
    });
};

const createCircle = (cx, cy, r, fill) => {

    return createElement('circle', {
        cx,
        cy,
        r,
        fill
    });
};

const loopGears = (gears, callback) => {

    const length = gears.length;

    gears.forEach((gear, index) => {

        const prevGear = gears[(length + index - 1) % length];
        const nextGear = gears[(index + 1) % length];

        callback(gear, prevGear, nextGear);
    });
};

const arcDescription = (radius, largeArcFlag, sweepFlag, endVector) => {

    return `A${radius} ${radius} 0 ${+largeArcFlag} ${+sweepFlag} ${endVector}`;
};

const renderGears = (data) => {

    let x = Infinity;
    let y = Infinity;
    let w = -Infinity;
    let h = -Infinity;

    const gears = data.map((params) => {

        const gear = new Gear(...params);
        const unit = params[2] + 5;

        x = Math.min(x, gear.x - unit);
        y = Math.min(y, gear.y - unit);
        w = Math.max(w, gear.x + unit);
        h = Math.max(h, gear.y + unit);

        return gear;
    });

    const firstGear = gears[0];

    w -= x;
    h -= y;

    const svg = createElement('svg', {
        width: w,
        height: h,
        viewBox: `${x} ${y} ${w} ${h}`,
        transform: `scale(1,-1)`
    });

    let chainPath = '';

    loopGears(gears, (gear, prevGear, nextGear) => {

        const gearVector = gear.getVector();
        const prevGearVector = prevGear.getVector().subtract(gearVector);
        const nextGearVector = nextGear.getVector().subtract(gearVector);

        gear.sweep = (prevGearVector.cross(nextGearVector) > 0);
    });

    loopGears(gears, (gear, prevGear, nextGear) => {

        const diffVector = gear.getVector().subtract(nextGear.getVector());

        let angle = 0;
        let x = 1 / diffVector.length;
        let y = x;

        if (gear.sweep === nextGear.sweep) {

            angle = Math.asin((gear.radius - nextGear.radius) * x);

            if (gear.sweep) {
                x = -x;
                y = -y;
                angle = -angle;
            }
        } else {

            angle = Math.asin((gear.radius + nextGear.radius) * x);

            if (gear.sweep) {
                x = -x;
                angle = -angle;
            } else {
                y = -y;
            }
        }

        const perpendicularVector = diffVector.rotate(angle + Math.PI / 2);

        gear.out = perpendicularVector.multiply(x * gear.radius).add(gear.getVector());
        nextGear.in = perpendicularVector.multiply(y * nextGear.radius).add(nextGear.getVector());
    });

    loopGears(gears, (gear, prevGear, nextGear) => {

        const largeArcFlag = (prevGear.out.subtract(nextGear.in).length < gear.in.subtract(gear.out).length);
        const arcPath = arcDescription(gear.radius, largeArcFlag, !gear.sweep, gear.out);

        const gearExterior = createCircle(gear.x, gear.y, gear.radius - 1.5, '#888');
        const gearInterior = createCircle(gear.x, gear.y, gear.radius - 4.5, '#666');
        const gearCenter = createCircle(gear.x, gear.y, 3, '#888');

        const gearTeeth = createPath({
            d: `M${gear.in}${arcPath}${arcDescription(gear.radius, !largeArcFlag, !gear.sweep, gear.in)}`,
            stroke: '#888',
            'stroke-width': 5
        });

        const chainParts = cloneElement(gearTeeth, {
            d: `M${gear.in}${arcPath}L${nextGear.in}`,
            stroke: '#222'
        });

        gear.teeth = gearTeeth;
        gear.chainParts = chainParts;

        chainPath += `${arcPath}L${nextGear.in}`;

        svg.appendChild(gearExterior);
        svg.appendChild(gearInterior);
        svg.appendChild(gearCenter);
        svg.appendChild(gearTeeth);
        svg.appendChild(chainParts);
    });

    const chain = cloneElement(firstGear.chainParts, {
        d: 'M' + firstGear.in + chainPath,
        'stroke-width': 2
    });

    const chainLength = chain.getTotalLength();
    const chainUnit = chainLength / Math.round(chainLength / (4 * Math.PI)) / 2;
    const animationOffset = 8 * chainUnit;

    loopGears(gears, (gear, prevGear) => {

        if (gear === firstGear) {
            gear.teethOffset = chainUnit;
            gear.chainOffset = 0;
        } else {
            gear.teethOffset = prevGear.teethOffset + prevGear.chainParts.getTotalLength();
            gear.chainOffset = prevGear.chainOffset + prevGear.chainParts.getTotalLength();
        }

        setAttributes(gear.teeth, {
            'stroke-dasharray': chainUnit,
            'stroke-dashoffset': gear.teethOffset
        });

        setAttributes(gear.chainParts, {
            'stroke-dasharray': chainUnit,
            'stroke-dashoffset': gear.chainOffset
        });

        const animate = createElement('animate', {
            attributeName: 'stroke-dashoffset',
            from: gear.teethOffset + animationOffset,
            to: gear.teethOffset,
            repeatCount: 'indefinite',
            dur: '1s'
        });

        const cloneAnimate = cloneElement(animate, {
            from: gear.chainOffset + animationOffset,
            to: gear.chainOffset
        });

        gear.teeth.appendChild(animate);
        gear.chainParts.appendChild(cloneAnimate);
    });

    svg.appendChild(chain);
    document.body.appendChild(svg);
};

var testCases = [
    [[0, 0, 16],  [100, 0, 16],  [100, 100, 12],  [50, 50, 24],  [0, 100, 12]],
    [[0, 0, 26],  [120, 0, 26]],
    [[100, 100, 60],  [220, 100, 14]],
    [[100, 100, 16],  [100, 0, 24],  [0, 100, 24],  [0, 0, 16]],
    [[0, 0, 60],  [44, 140, 16],  [-204, 140, 16],  [-160, 0, 60],  [-112, 188, 12], [-190, 300, 30],  [30, 300, 30],  [-48, 188, 12]],
    [[0, 128, 14],  [46.17, 63.55, 10],  [121.74, 39.55, 14],  [74.71, -24.28, 10], [75.24, -103.55, 14],  [0, -78.56, 10],  [-75.24, -103.55, 14],  [-74.71, -24.28, 10], [-121.74, 39.55, 14],  [-46.17, 63.55, 10]],
    [[367, 151, 12],  [210, 75, 36],  [57, 286, 38],  [14, 181, 32],  [91, 124, 18], [298, 366, 38],  [141, 3, 52],  [80, 179, 26],  [313, 32, 26],  [146, 280, 10], [126, 253, 8],  [220, 184, 24],  [135, 332, 8],  [365, 296, 50],  [248, 217, 8], [218, 392, 30]]
];

function clear() {
    var buttons = document.createElement('div');
    document.body.innerHTML = "";
    document.body.appendChild(buttons);
    testCases.forEach(function (data, i) {
        var button = document.createElement('button');
        button.innerHTML = String(i);
        button.onclick = function () {
            clear();
            renderGears(data);
            return false;
        };
        buttons.appendChild(button);
    });
}

clear();


1
आप इस टूल का उपयोग करके 250 से अधिक बाइट्स बचा सकते हैं ।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.