একটি বেজিয়ার বক্ররেখা অ্যানিমেটেড অঙ্কন


39

আপনার কাজটি নিয়ন্ত্রণ পয়েন্টগুলি সরবরাহ করে একটি বেজিয়ার বক্ররেখা আঁকা। একমাত্র মানদণ্ডটি হল আপনাকে প্রাথমিক কন্ট্রোল পয়েন্ট থেকে শেষের দিকে কীভাবে বক্র আঁকতে হবে তা আপনাকে প্রকৃতপক্ষে প্রদর্শন করতে হবে।

criterias

  • ফলাফলটি অ্যানিমেটেড করতে হবে, উদাহরণস্বরূপ এটি কোনওভাবে অঙ্কন প্রক্রিয়াটি প্রদর্শন করতে হবে। আপনি অ্যানিমেশনটি যেভাবে করেন তা অপ্রাসঙ্গিক, এটি একটি উত্পন্ন করতে পারে .gif, এটি একটি উইন্ডোতে আঁকতে পারে, বা এএসসিআইআই ফলাফল তৈরি করতে পারে (এবং সম্ভবত প্রতিটি ড্রয়ের পরে পর্দা সাফ করা) ইত্যাদি etc.
  • এটিতে কমপক্ষে 64৪ টি নিয়ন্ত্রণ পয়েন্টকে সমর্থন করতে হবে।
  • এটি একটি জনপ্রিয়তা প্রতিযোগিতা, সুতরাং আপনি আরও বেশি কিছু পেতে আপনার প্রোগ্রামে কিছু অতিরিক্ত বৈশিষ্ট্য যুক্ত করতে চাইতে পারেন। (উদাহরণস্বরূপ আমার উত্তর নিয়ন্ত্রণ পয়েন্টগুলি আঁকবে এবং চিত্রটি কীভাবে তৈরি করা যায় সে সম্পর্কে কিছু দৃশ্য সহায়তা)
  • বিজয়ী সর্বশেষ বৈধ জমা দেওয়ার 7 দিন পরে সর্বাধিক উন্নত বৈধ উত্তর।
  • আমার জমাটি বৈধ হিসাবে গণনা করে না।

কিভাবে একটি Bierzier বক্ররেখা আঁকা

ধরুন আমরা 100 টি পুনরাবৃত্তি আঁকতে চাই। nবক্ররেখার দিকটি পেতে আপনি নিম্নলিখিত অ্যালগরিদমটি ব্যবহার করতে পারেন:

1. Take each adjanced control point, and draw a line between them
2. Divide this line by the number of iterations, and get the nth point based on this division.
3. Put the points you've got into a separate list. Let's call them "secondary" control points.
4. Repeat the whole process, but use these new "secondary" control points. As these points have one less points at each iteration eventually only one point will remain, and you can end the loop.
5. This will be nth point of the Bézier curve

এটি লিখিত লেখাটি বুঝতে অসুবিধা হতে পারে, সুতরাং এটি ভিজ্যুয়ালাইজ করতে সহায়তা করার জন্য এখানে কিছু চিত্র রয়েছে:

দুটি নিয়ন্ত্রণ পয়েন্টের জন্য (কালো বিন্দুতে দেখানো হয়েছে) আপনার কাছে কেবলমাত্র একটি লাইন অন্তরঙ্গভাবে (কালো রেখা) রয়েছে। এই রেখাকে পুনরাবৃত্তির সংখ্যার সাথে ভাগ করে এবং nপঞ্চম পয়েন্ট পাওয়ার ফলে বক্ররের পরবর্তী বিন্দুতে (লাল দেখানো) ফলাফল হবে:

দুটি বিন্দু

তিনটি নিয়ন্ত্রণ পয়েন্টের জন্য, আপনাকে প্রথমে প্রথম এবং দ্বিতীয় নিয়ন্ত্রণ বিন্দুর মধ্যে লাইনটি ভাগ করতে হবে, তারপরে লাইনটি দ্বিতীয় এবং তৃতীয় নিয়ন্ত্রণ বিন্দুর মধ্যে ভাগ করতে হবে। আপনি নীল বিন্দু দিয়ে চিহ্নিত পয়েন্ট পাবেন।

তারপরে, আপনার এখনও দুটি পয়েন্ট রয়েছে, আপনাকে এই দুটি পয়েন্ট (চিত্রের নীল) এর মধ্যে একটি লাইন আঁকতে হবে এবং বক্ররেখার জন্য পরবর্তী পয়েন্টটি পেতে আবার ভাগ করুন:

তিনটি পয়েন্ট

আপনি আরও নিয়ন্ত্রণ পয়েন্ট যুক্ত করার সাথে অ্যালগরিদম একই থাকে, তবে আরও বেশি করে পুনরাবৃত্তি করতে হবে। চারটি পয়েন্ট সহ এটি দেখতে কেমন হবে তা এখানে:

চার পয়েন্ট

এবং পাঁচটি পয়েন্ট:

পাঁচটি পয়েন্ট

আপনি আমার সমাধানটিও পরীক্ষা করতে পারেন, যা এই চিত্রগুলি তৈরি করতে ব্যবহৃত হয়েছিল, বা উইকিপিডিয়ায় বাজিয়ার বক্ররেখা উত্পন্ন সম্পর্কে আরও পড়ুন


"এটি কমপক্ষে control৪ টি নিয়ন্ত্রণ পয়েন্টকে সমর্থন করতে হবে।" এটি কি অতিরিক্ত নয়? আমি ভাবব যে 6 টি নিয়ন্ত্রণ পয়েন্ট যথেষ্ট হবে।
ডেভিডসি

@ ডেভিডকার্যাহার: অ্যালগরিদমটি কার্যকর করা এতটা কঠিন নয়, এবং এটি O(n^2)সময় এবং জায়গাতে চলে (যেখানে nনিয়ন্ত্রণ পয়েন্টগুলির সংখ্যা রয়েছে), তাই 64৪ বেশি হওয়া উচিত নয় (এবং ফলাফলগুলি প্রচুর নিয়ন্ত্রণের সাথে সত্যিই দুর্দান্ত হতে পারে) পয়েন্ট)। অবশ্যই যদি কোনও নির্বাচিত ভাষার সাথে সত্যিকারের প্রযুক্তিগত সীমাবদ্ধতা থাকে যা এটি কয়েক ডিগ্রির বেশি দিয়ে এটিকে সমাধান করা অসম্ভব / খুব অবাস্তব করে তোলে, তবে আমি এটি হ্রাস করে খুশি।
SztupY

1
পিছনে যাওয়ার বা অবিরাম পুনরাবৃত্তি করার পরিবর্তে একটি দুর্দান্ত প্রকরণ। শেষে প্রথম পয়েন্টটি ড্রপ করুন এবং অন্য এলোমেলো পয়েন্টটি চয়ন করুন। লাইন প্রসারিত রাখুন।
কোয়ান্টিনুক

উত্তর:


18

মাত্র তিন লাইনে নম্বর নিয়ন্ত্রণ পয়েন্টের কোনও কঠোর সীমা ছাড়াই গণিতের পুনরাবৃত্তভাবে সম্পন্ন:

ctrlPts = {{0, 0}, {1, 1}, {2, 0}, {1, -1}, {0, 0}};
getLines[x_List] := Partition[x, 2, 1];
partLine[{a_, b_}, t_] := t a + (1 - t) b;
f[pts_, t_] := NestList[partLine[#, t] & /@ getLines@# &, pts, Length@pts- 1]

এটি দেখানো গণনার চেয়ে বেশি জড়িত!:

color[x_] := ColorData[5, "ColorList"][[x[[1]]]]
Animate[Graphics[{PointSize[.03], ,
        MapIndexed[{color@#2, Point/@ #1,Line@#1} &, f[ctrlPts,t]],
        Red, Point@Last@f[ctrlPts, t],
        Line@Flatten[(Last@f[ctrlPts, #]) & /@ Range[0, t, 1/50], 1]}], {t, 0, 1}]

ক্যালক অংশের জন্য কোড বিচ্ছিন্নকরণ (ধরণের):

getLines[x_List] := Partition[x, 2, 1]; (* Takes a list of points { pt1, pt2, pt...} 
                                           as input and returns {{pt1,pt2}, {pt2,pt3} ...}
                                           which are the endpoints for the successive
                                           lines between the input points *)

partLine[{a_, b_}, t_] := t a + (1 - t) b;(* Takes two points and a "time" as input 
                                             and calculates
                                             a linear interpolation between them*)

f[pts_, t_] := NestList[partLine[#, t] & /@ getLines@# &, pts, Length@pts- 1]
                                          (* This is where the meat is :) 
     Takes a list of n points and a "time" as input.
     Operates recursively on the previous result n-1 times, preserving all the results 
     Each time it does the following with the list {pt1, pt2, pt3 ...} received:
           1) Generates a list {{pt1, pt2}, {pt2, pt3}, {pt3, pt4} ...}
           2) For each of those sublists calculate the linear interpolation at time "t",
              thus effectively reducing the number of input points by 1 in each round.
     So the end result is a list of lists resembling:
     {{pt1, pt2, pt3 ...}, {t*pt1+(1-t)*pt2, t*pt2+(1-t)*pt3,..}, {t*pt12+(1-t)*pt23, ..},..}
                             --------------   ---------------         
                                  pt12              pt23
     And all those are the points you see in the following image:

এখানে চিত্র বর্ণনা লিখুন

অ্যানিমেশন চলাকালীন আরও কয়েকটি লাইন দিয়ে আপনি নিয়ন্ত্রণ পয়েন্টগুলি ইন্টারেক্টিভভাবে টেনে আনতে পারেন:

Manipulate[
 Animate[Graphics[{
    PointSize[.03], Point@pts,
    MapIndexed[{color@#2, Point /@ #1, Line@#1} &, f[pts, t]],
    Red, Point@Last@f[pts, t], Line@Flatten[(Last@f[pts, #]) & /@ Range[0, t, 1/50], 1]}, 
   PlotRange -> {{0, 2}, {-1, 1}}], {t, 0, 1}],
  {{pts, ctrlPts}, Locator}]

এখানে সবুজ পয়েন্ট টেনে আনছেন:

এখানে চিত্র বর্ণনা লিখুন

BTW, 3D মধ্যে একই কোড রান পরিবর্তন ছাড়াই (ম্যাথামেটিকাল Geeks জন্য আপনি শুধুমাত্র প্রতিস্থাপন আছে Graphics[]দ্বারা Graphics3D[]এবং একটি তৃতীয় নিয়ন্ত্রণ পয়েন্ট তালিকায় তুল্য যোগ):

এখানে চিত্র বর্ণনা লিখুন

বিশেষ দ্রষ্টব্য:

বেজিয়ার্স আঁকার জন্য বেশ কয়েকটি আদিম আছে বলে অবশ্যই ম্যাথামেটিকায় এই কুলজের প্রয়োজন নেই:

Graphics[{BSplineCurve[ctrlPts], Green, Line[ctrlPts], Red,  Point[ctrlPts]}]

গণিত গ্রাফিক্স


4
এমন একটি গণিতের সমাধানটি দেখে খুব ভাল লাগল যা এর বিশাল লাইব্রেরিতে খুব বেশি নির্ভর করে না
izabera

3
Instructions for testing this answer without Mathematica installed: 1) Download http://pastebin.com/qU9rztdf and save it as *.CDF 2) Dowload the free CDF environment from Wolfram Research at https://www.wolfram.com/cdf-player/ (not a small file) 3) "Alt + Left-Click" on Windows or "CMD + Left-Click" on Mac for creating/deleting control points 4) Control points can also be dragged!
ডাঃ বেলিসারিয়াস

15

পাইথন

অবশ্যই সবচেয়ে দক্ষ বা সুন্দর কোড নয় তবে এটি মজাদার ছিল। হিসাবে চালান

$> python thisscript.py

নিয়ন্ত্রণ পয়েন্টগুলি এখনই এলোমেলোভাবে উত্পাদিত হয়েছে তবে স্টিডিন বা ফাইল ইনপুটকে অনুমতি দেওয়ার জন্য এটি বাড়ানো তুচ্ছ।

  • নিয়ন্ত্রণ পয়েন্টগুলি দেখায়
  • পুনরাবৃত্তিগুলি দেখায়
  • প্রতিটি পুনরাবৃত্তির জন্য আলাদা রঙ

বোনাস হিসাবে এমন একটি অন্তহীন মোড রয়েছে যা দিন না হলেও কয়েক ঘন্টা বিনোদনের জন্য গ্যারান্টিযুক্ত!

Matplotlib প্রয়োজন হয় এবং আপনি যদি ফলাফলের জিআইএফ সংরক্ষণ করতে চান তবে চিত্রম্যাগিক। Control৪ টি কন্ট্রোল পয়েন্ট পর্যন্ত পরীক্ষা করা হয়েছে (প্রচুর পয়েন্টের সাথে খুব ধীর গতিতে চলে!)

একটি উদাহরণ আউটপুট gif

import matplotlib
matplotlib.use('GTkAgg')
import pylab as pl
from math import sin,cos,pi
from random import random
import os
import time

class Point:
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def __repr__(self):
        return "[{:.3f},{:.3f}]".format(self.x,self.y)
    def __str__(self):
        return self.__repr__()

class Path:
    def __init__(self,points):
        self.points=points
    def interpolate(self,u): # interpolate the path, resulting in another path with one point less in length
        pts = [None]*(len(self.points)-1)
        for i in range(1,len(self.points)):
            x = self.points[i-1].x + u*( self.points[i].x - self.points[i-1].x)
            if (self.points[i-1].x == self.points[i].x): # vertical line
                y = self.points[i-1].y + u*( self.points[i].y - self.points[i-1].y)
            else:
                y = self.points[i-1].y + (self.points[i].y - self.points[i-1].y)/(self.points[i].x - self.points[i-1].x)*( x - self.points[i-1].x)
            pts[i-1] = Point(x,y)
        return Path(pts)

    def interpolate_all(self,u): # interpolate all the paths
        paths = [None]*len(self.points)
        paths[0]=self
        for i in range(1,len(paths)):
            paths[i] = paths[i-1].interpolate(u)
        return paths

    def draw(self,ax,color,*args,**kwargs):
        x = [ p.x for p in self.points]
        y = [ p.y for p in self.points]
        ax.plot(x,y,*args,color=color,**kwargs)
        ax.scatter([p.x for p in self.points], [p.y for p in self.points],color=color)  

    def __str__(self):
        return str(self.points)

def bezier(path,ustep,ax,makeGif):
    if makeGif:
        os.system("mkdir -p tempgif")
    u=0.
    x=[] # x coordinate list for the bezier path point
    y=[] # y coordinate list for the bezier path point
    pl.ion()
    pl.show()
    n=0
    while u < 1.+ustep: # and not u <= 1.0 to get rid of rounding errors 
        ax.cla()
        paths = path.interpolate_all(u)
        x.append(paths[-1].points[0].x)
        y.append(paths[-1].points[0].y)
        u+=ustep
        for i in range(len(paths)):
            color = pl.cm.jet(1.*i/len(paths)) # <-- change colormap here for other colors, for a list of available maps go to http://wiki.scipy.org/Cookbook/Matplotlib/Show_colormaps
            paths[i].draw(ax,color=color,lw=2) # draw all the paths
        ax.plot(x,y,color='red',lw=5) # draw the bezier curve itself
        pl.draw()
        if makeGif:
            pl.savefig("tempgif/bezier_{:05d}.png".format(n))
            n+=1
    if makeGif:
        print("Creating your GIF, this can take a while...")
        os.system("convert -delay 5 -loop 0 tempgif/*.png "+makeGif)
        os.system("rm -r tempgif/")
        print("Done.")
    pl.ioff()

def getPtsOnCircle(R,n):
    x = [None]*(n+1)
    y = [None]*(n+1)
    for i in range(n+1):
        x[i] = R*cos(i*2.*pi/n)
        y[i] = R*sin(i*2.*pi/n)
    return x,y

def getRndPts(n):
    x = [ random() for i in range(n) ]
    y = [ random() for i in range(n) ]
    return x,y

def run(ax,x,y,makeGif=False):
    ctrlpoints = [ Point(px,py) for px,py in zip(x,y) ]
    path = Path(ctrlpoints)
    bezier(path,0.01,ax,makeGif) # 0.01 is the step size in the interval [0,1]

def endless_mode(ax):
    while True:
        x,y = getRndPts( int(5+random()*10) )
        run(ax,x,y)
        pl.draw()
        time.sleep(0.5) # pause for a moment to gaze upon the finished bezier curve
def main():
    fig = pl.figure(figsize=(6,6)) # <-- adjust here for figure size
    fig.subplots_adjust(0,0,1,1)
    ax = fig.add_subplot(111)
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    opt = raw_input("[s]ingle run or [e]ndless mode? ")
    if opt=='s':
        gifname = raw_input("Name of output GIF (leave blank for no GIF): ")
        x,y = getRndPts(15)
        run(ax,x,y,gifname if gifname != "" else False)
        pl.show()
    elif opt=='e':
        endless_mode(ax)
    else:
        print("Invalid input: "+opt)

main()

এটা ছিল চিত্তাকর্ষক। অন্যদের জন্য একটি নোট: পাইজিটিके কেবল ২.6 এবং ২.7 এর জন্য উপলব্ধ। এবং যদিও কোথাও বলা হয়নি, আপনার পাইথন ইন্টারপ্রেটারের কাছে আপনার সিস্টেমে জিটিকে + ইনস্টল করা সংস্করণটি অবশ্যই ২.x হতে হবে 2.
primo

11

পুনশ্চ

একটি উত্পন্ন gifকরতে, নিশ্চিত করুন যে 'এমিটপেজগুলি' সত্য হিসাবে সংজ্ঞায়িত হয়েছে এবং:

gs -sDEVICE=png16 -g500x500 -o bezan%03d.png bezanim.ps
convert bezan*.png bezan.gif

অতিরিক্ত সুবিধাগুলি:

  • কনফিগারযোগ্য বাউন্ডিং বক্স
  • 2 জেনারেটর: এলোমেলো পয়েন্ট, এলোমেলোভাবে অনুমতি দেওয়া এলোমেলোভাবে বেজিয়ারকে ফ্ল্যাট করা
  • "ওভারলে" অ্যানিমেশন (যেখানে এটি কোনও কিছুই মুছে না)।
  • alচ্ছিক 'শোপেজ' ( gifস্ক্রিন পূর্বরূপের জন্য বাদ দেওয়ার জন্য ব্যবহার করুন)

ঘোস্টস্ক্রিপ্ট এবং পয়েন্টের বৃহত্তর সেটগুলি ব্যবহার করে, অন-স্ক্রিন পূর্বরূপ উত্পন্ন চিত্রগুলির থেকে খুব আলাদা, কারণ আপনি প্রতিটি বিন্দুতে "একত্রিত" রেখা দেখতে পারেন।

সাধারণ বিন্দুগুলির সেট, স্কেলড, ব্যবহার করে png48:

সরল পয়েন্ট সেট

ওভারলে সহ সহজ সেট:

ওভারলে সঙ্গে সহজ সেট

প্রচুর পয়েন্ট, ওভারলে অ্যানিমেশন:

ওভারলে অ্যানিমেশন

অ ওভারলে:

অ আস্তরণ

কোড:

%!
/iterations 100 def
%/Xdim 612 def
%/Ydim 792 def
/Xdim 400 def
/Ydim 400 def
/scalepage {
    100 100 translate
    %1 5 scale % "tron"?
    1 3 dup dup scale div currentlinewidth mul setlinewidth
} def scalepage
/gen 2 def  % 0:rand points  1:rand permuted bezier
            % 2:special list
/genN 6 def % number of generated points
/overlay true def
/emitpages false def
/emitpartials false def
/.setlanguagelevel where { pop 2 .setlanguagelevel } if

/pairs { % array-of-points  .  array-of-pairs-of-points
    [ exch 0 1 2 index length 2 sub { % A i
        2 copy 2 getinterval % A i A_[i..i+1]
        3 1 roll pop % A_[i..i+1] A
    } for pop ]
} def

/drawpairs {
    gsave
    dup 1 exch length B length div sub setgray
    {
        aload pop
        aload pop moveto
        aload pop lineto
        stroke
        %flushpage
    } forall
    %flushpage
    %emitpartials { copypage } if
    grestore
} def

/points { % array-of-pairs  .  array-of-points
    [ exch { % pair
        [ exch
        aload pop % p0 p1
        aload pop 3 2 roll aload pop % p1x p1y p0x p0y
        exch % p1x p1y p0y p0x
        4 3 roll % p1y p0y p0x p1x
        exch % p1y p0y p1x p0x
        2 copy sub n mul add exch pop % p1y p0y p0x+n(p1x-p0x)
        3 1 roll % p0x+n(p1x-p0x) p1y p0y
        2 copy sub n mul add exch pop % p0x+n(p1x-p0x) p0y+n(p1y-p0y)
        ]
    } forall ]
} def

/drawpoints {
    gsave
    dup length B length div setgray
    {
        newpath
        aload pop 2 copy moveto currentlinewidth 3 mul 0 360 arc fill
        %flushpage
    } forall
    %flushpage
    emitpartials { copypage } if
    grestore
} def

/anim {
    /B exch def
    /N exch def
    /Bp B pairs def
    Bp drawpairs
    1 0 0 setrgbcolor
    B 0 get aload pop moveto
    0 1 N div 1 { /n exch def
        B
        {
            dup length 1 eq { exit } if
            dup drawpoints
            pairs dup drawpairs
            points
        } loop
        aload pop
        aload pop
        2 copy
        gsave
            newpath
            2 copy moveto currentlinewidth 3 mul 0 360 arc fill
        grestore
        lineto currentpoint stroke 2 copy moveto
        gsave
            count dup 1 add copy
            3 1 roll moveto
            2 idiv 1 sub {
                lineto
            } repeat
            pop
            stroke
        grestore
        emitpages {
            currentpoint
            currentrgbcolor
            overlay { copypage }{ showpage scalepage } ifelse
            setrgbcolor
            moveto
        }{
            flushpage 10000 { 239587 23984 div pop } repeat 
            flushpage 4000 { 239587 23984 div pop } repeat
            overlay not {
                erasepage Bp drawpairs
            } if
            %flushpage
        } ifelse
    } for
    moveto N { lineto } repeat stroke
} def

% "main":

iterations
[
    { [ genN { [ rand Xdim mod rand Ydim mod ] } repeat ] }
    {
        40 setflat
        rand Xdim mod rand Ydim mod moveto
        genN 1 sub 3 div ceiling cvi
            { 3 { rand Xdim mod rand Ydim mod } repeat curveto } repeat
        flattenpath
        [{2 array astore}dup{}{}pathforall]
        [exch dup 0 get exch 1 1 index length 1 sub getinterval {
            rand 2 mod 0 eq { exch } if
        } forall]
        0 genN getinterval
    }
    {
        [
            [10 10]
            [100 10]
            [100 100]
            [10 100]
            [10 40]
            [100 40]
            [130 10]
            [50 50]
            [80 50]
            [110 30]
            [20 50]
            [70 50]
            [60 50]
            [10 10]
            [40 50]
            [30 50]
            [10 30]
            [90 50]
            [10 50]
            [120 20]
            [10 20]
        ] 0 genN getinterval
    }
] gen get exec

newpath anim

stroke

ওভারলে অ্যানিমেশনটি একটি আধুনিক আর্ট ড্রাগনের মতো দেখাচ্ছে
স্জটুপওয়াই

বেশ সুন্দর বন্য! ভূস্ট্রিপ্টের সাথে প্রাকদর্শন করার সময়, স্ট্রোবস্কোপিক প্রভাবের কারণে মুছে ফেলা খুব কঠিন ছিল, তাই আমি সেগুলি সরিয়ে দেওয়ার চেষ্টা করেছি। তবে ওভারলেটি সহ, ভুতের স্ক্রিপ্ট পূর্বরূপটি এখনও খুব "চটকদার"। মৃগী রোগের জন্য সম্ভবত উপযুক্ত নয়। :(
লুসার droog

আপনার কম নিয়ন্ত্রণ পয়েন্ট সহ কয়েকটি চিত্র যুক্ত করা উচিত। কী চলছে তা দেখতে মোটামুটি শক্ত।
primo

হ্যাঁ. ভাল ধারণা.
লুসার droog

9

রুবি + আরম্যাগিক

অতিরিক্ত বৈশিষ্ট্য:

  • নিয়ন্ত্রণ পয়েন্টগুলি দেখায়
  • প্রতিটি পুনরাবৃত্তি দেখায়
  • প্রতিটি পুনরাবৃত্তির জন্য বিভিন্ন রঙ ব্যবহার করে

STDIN থেকে পয়েন্টগুলি প্রেরণে ব্যবহার করতে:

$ echo "300 400 400 300 300 100 100 100 200 400" | ./draw.rb

ফলাফল ভিতরে থাকবে result.gif:

পাঁচটি পয়েন্ট

এখানে 12 + 1 পয়েন্ট সহ আরও একটি রান রয়েছে:

$ echo "100 100 200 200 300 100 400 200 300 300 400 400 300 500 200 400 100 500 0   400 100 300 0   200 100 100" | ./draw.rb

তেরো পয়েন্ট

কোড

এটি না গল্ফ, না খুব পাঠযোগ্য, এর জন্য দুঃখিত sorry

draw.rb

#!/usr/bin/env ruby
require 'rubygems'
require 'bundler/setup'
Bundler.require(:default)

ITERATIONS = 100

points = ARGF.read.split.map(&:to_i).each_slice(2).to_a
result = []

def draw_line(draw,points)
  points.each_cons(2) do |a,b|
    draw.line(*a, *b)
  end
end

def draw_dots(draw,points,r)
  points.each do |x,y|
    draw.ellipse(x,y,r,r,0,360)
  end
end

canvas = Magick::ImageList.new

0.upto(ITERATIONS) do |i|
  canvas.new_image(512, 512)

  draw = Magick::Draw.new

  draw.stroke('black')
  draw.stroke_width(points.length.to_f/2)
  draw_line(draw,points)
  draw_dots(draw,points,points.length)

  it = points.dup
  while it.length>1
    next_it = []
    it.each_cons(2) do |a,b|
      next_it << [b[0]+(a[0]-b[0]).to_f/ITERATIONS * i, b[1]+(a[1]-b[1]).to_f/ITERATIONS * i]
    end
    draw.stroke("hsl(#{360/points.length.to_f*next_it.length},100,100)")
    draw.fill("hsl(#{360/points.length.to_f*next_it.length},100,100)")
    draw.stroke_width(next_it.length.to_f/2)
    draw_line(draw,next_it)
    draw_dots(draw,next_it,next_it.length)
    it = next_it
  end

  result << it.first

  draw.stroke("hsl(0,100,100)")
  draw.fill("hsl(0,100,100)")
  draw.stroke_width(points.length)
  draw_line(draw,result)
  draw_dots(draw,[it.first],points.length*2)

  draw.draw(canvas)
end

canvas.write('result.gif')

Gemfile

source "https://rubygems.org"
gem 'rmagick', '2.13.2'

8

জাভা

অ্যান্টি গ্রেন জ্যামিতির অভিযোজিত মহকুমার অ্যালগরিদম ব্যবহার করে ।

কোড ইন্টারেক্টিভ এবং ব্যবহারকারীকে মাউস দিয়ে চারটি নোড টেনে আনতে দেয়।

public class SplineAnimation extends JPanel implements ActionListener, MouseInputListener {
    int     CANVAS_SIZE             = 512;
    double  m_distance_tolerance    = 1;
    double  m_angle_tolerance       = 1;
    int     curve_recursion_limit   = 1000;

    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        f.setContentPane(new SplineAnimation());

        f.pack();
        f.setResizable(false);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    // Graphics.
    BufferedImage   im      = new BufferedImage(CANVAS_SIZE, CANVAS_SIZE, BufferedImage.TYPE_INT_ARGB);
    Graphics2D      imageG  = im.createGraphics();
    Graphics2D      g       = null;
    Ellipse2D       dot     = new Ellipse2D.Double();
    Line2D          line    = new Line2D.Double();
    Path2D          path    = new Path2D.Double();

    // State.
    Point2D[]       pts     = {new Point2D.Double(10, 10), new Point2D.Double(CANVAS_SIZE / 8, CANVAS_SIZE - 10), new Point2D.Double(CANVAS_SIZE - 10, CANVAS_SIZE - 10), new Point2D.Double(CANVAS_SIZE / 2, 10)};
    double          phase   = 0;
    private int     dragPt;
    private double  f;
    private int     n       = 0;

    public SplineAnimation() {
        super(null);
        setPreferredSize(new Dimension(CANVAS_SIZE, CANVAS_SIZE));
        setOpaque(false);

        // Prepare stuff.
        imageG.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        imageG.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        imageG.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        imageG.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        imageG.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
        imageG.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        imageG.translate(0.5, 0.5);
        addMouseListener(this);
        addMouseMotionListener(this);

        // Animate!
        new javax.swing.Timer(16, this).start();
    }

    @Override
    public void paintComponent(Graphics g) {
        this.g = (Graphics2D)getGraphics();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // Drawable yet?
        if (g == null)
            return;

        // Clear.
        imageG.setColor(Color.WHITE);
        imageG.fillRect(0, 0, CANVAS_SIZE + 1, CANVAS_SIZE + 1);

        // Update state.
        f = 0.5 - 0.495 * Math.cos(phase += Math.PI / 100);

        // Render.
        path.reset();
        path.moveTo(pts[0].getX(), pts[0].getY());
        recursive_bezier(0, pts[0].getX(), pts[0].getY(), pts[1].getX(), pts[1].getY(), pts[2].getX(), pts[2].getY(), pts[3].getX(), pts[3].getY());
        path.lineTo(pts[3].getX(), pts[3].getY());

        imageG.setPaint(Color.BLACK);
        imageG.draw(path);
        g.drawImage(im, 0, 0, null);

//      if (phase > Math.PI)
//          System.exit(0);
//      save("Bezier" + n++ + ".png");
    }

    private void save(String filename) {
        paint(im.getGraphics());
        try {
            ImageIO.write(im, "PNG", new File(filename));
        }
        catch (IOException e) {}
    }

    // Modified algorithm from Anti Grain Geometry.
    // http://www.antigrain.com/research/adaptive_bezier/index.html
    private void recursive_bezier(int level, double x1, double y1, double x2, double y2, double x3, double y3, double x4,
            double y4) {
        if (level > curve_recursion_limit)
            return;

        // Calculate all the mid-points of the line segments
        // ----------------------
        double x12 = x1 + (x2 - x1) * f;
        double y12 = y1 + (y2 - y1) * f;
        double x23 = x2 + (x3 - x2) * f;
        double y23 = y2 + (y3 - y2) * f;
        double x34 = x3 + (x4 - x3) * f;
        double y34 = y3 + (y4 - y3) * f;
        double x123 = x12 + (x23 - x12) * f;
        double y123 = y12 + (y23 - y12) * f;
        double x234 = x23 + (x34 - x23) * f;
        double y234 = y23 + (y34 - y23) * f;
        double x1234 = x123 + (x234 - x123) * f;
        double y1234 = y123 + (y234 - y123) * f;

        if (level > 0) // Enforce subdivision first time
        {
            // Try to approximate the full cubic curve by a single straight line
            // ------------------
            double dx = x4 - x1;
            double dy = y4 - y1;

            double d2 = Math.abs((x2 - x4) * dy - (y2 - y4) * dx);
            double d3 = Math.abs((x3 - x4) * dy - (y3 - y4) * dx);

            double da1, da2;

            if ((d2 + d3) * (d2 + d3) <= m_distance_tolerance * (dx * dx + dy * dy)) {
                // If the curvature doesn't exceed the distance_tolerance
                // value we tend to finish subdivisions.
                // ----------------------

                // Angle & Cusp Condition
                // ----------------------
                double a23 = Math.atan2(y3 - y2, x3 - x2);
                da1 = Math.abs(a23 - Math.atan2(y2 - y1, x2 - x1));
                da2 = Math.abs(Math.atan2(y4 - y3, x4 - x3) - a23);
                if (da1 >= Math.PI)
                    da1 = 2 * Math.PI - da1;
                if (da2 >= Math.PI)
                    da2 = 2 * Math.PI - da2;

                if (da1 + da2 < m_angle_tolerance) {
                    // Finally we can stop the recursion
                    // ----------------------
                    path.lineTo(x1234, y1234);
                    return;
                }
            }
        }

        // Continue subdivision
        // ----------------------
        recursive_bezier(level + 1, x1, y1, x12, y12, x123, y123, x1234, y1234);
        recursive_bezier(level + 1, x1234, y1234, x234, y234, x34, y34, x4, y4);

        // Draw the frame.
        float c = 1 - (float)Math.pow(1 - Math.sqrt(Math.min(f, 1 - f)), level * 0.2);
        imageG.setPaint(new Color(1, c, c));
        line.setLine(x1, y1, x2, y2);
        imageG.draw(line);
        line.setLine(x2, y2, x3, y3);
        imageG.draw(line);
        line.setLine(x3, y3, x4, y4);
        imageG.draw(line);
        line.setLine(x12, y12, x23, y23);
        imageG.draw(line);
        line.setLine(x23, y23, x34, y34);
        imageG.draw(line);
        node(level + 1, x1234, y1234, level == 0? Color.BLUE : Color.GRAY);
    }

    private void node(int level, double x, double y, Color color) {
        double r = 20 * Math.pow(0.8, level);
        double r2 = r / 2;
        dot.setFrame(x - r2, y - r2, r, r);
        imageG.setPaint(color);
        imageG.fill(dot);
    }

    @Override
    public void mouseClicked(MouseEvent e) {}

    @Override
    public void mouseEntered(MouseEvent e) {}

    @Override
    public void mouseExited(MouseEvent e) {}

    @Override
    public void mousePressed(MouseEvent e) {
        Point mouse = e.getPoint();

        // Find the closest point;
        double minDist = Double.MAX_VALUE;
        for (int i = 0; i < pts.length; i++) {
            double dist = mouse.distanceSq(pts[i]);
            if (minDist > dist) {
                minDist = dist;
                dragPt = i;
            }
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {}

    @Override
    public void mouseDragged(MouseEvent e) {
        pts[dragPt] = e.getPoint();
    }

    @Override
    public void mouseMoved(MouseEvent e) {}
}

এখানে চিত্র বর্ণনা লিখুন


HOLYSHIT! সেটা খুবই ভালো. +1
লুসার droog

6

এইচটিএমএল 5 + জাভাস্ক্রিপ্ট + সিএসএস

তাই আমি এটি দীর্ঘকাল আগে করেছি (ফাইলটির সর্বশেষ পরিবর্তিত তারিখটি 9/21/2012 ছিল)। খুশি যে আমি এটি রেখেছি। দুর্ভাগ্যক্রমে এটি তার বর্তমান অবস্থায় 4 টি নিয়ন্ত্রণ পয়েন্টকে সমর্থন করে তবে আমি এটিতে কাজ করছি।

সম্পাদনা: যদিও ইউআই কেবল 4 টি নিয়ন্ত্রণ পয়েন্টকে সমর্থন করে, অন্তর্নিহিত ফাংশন ( animateConstruction) একটি নির্বিচার সংখ্যক নিয়ন্ত্রণ পয়েন্টকে সমর্থন করে। যদিও কোডটি খুব অকার্যকর হওয়ায় আমি 10 টিরও বেশি এটি করার পরামর্শ দেব না। (আমি 25 দিয়ে চেষ্টা করেছি এবং টাস্ক ম্যানেজার ব্যবহার করে ট্যাবটি হত্যা করতে হয়েছিল) যদি এইটিকে বৈধ জমা হিসাবে গণনা করা হয় তবে আমি কোডটি সংশোধন করার পরিকল্পনা করছি না।

দ্রষ্টব্য: আমি তখন এক নির্বোধ শখের মানুষ ছিলাম। কোডটি এতগুলি স্তরে ভুল (সেমিকোলনগুলির অভাব এবং ব্যবহার সহ eval)।

ব্যবহার করা

কোডটিকে একটি html ফাইল হিসাবে সংরক্ষণ করুন এবং এটি গুগল ক্রোম বা জেএসফিডিতে খুলুন
আপনার যদি 4 বা তার চেয়ে কম নিয়ন্ত্রণ পয়েন্টের প্রয়োজন হয় তবে ডানদিকে প্যারামিটারগুলি প্রবেশ করুন, তারপরে "নির্মাণ মোড" চয়ন করুন এবং নীচে বামদিকে "অ্যানিমেট" টিপুন।
আপনার যদি আরও নিয়ন্ত্রণ পয়েন্টগুলির প্রয়োজন হয় তবে animateConstructionফাংশনটি কল করুন । এটি আর্গুমেন্ট হিসাবে স্থানাঙ্কের একটি অ্যারে লাগে (2-আইটেম অ্যারে)। (যেমন animateConstruction([[0,0],[500,0],[0,500]]) দ্রষ্টব্য অঞ্চলটি 500x500, এবং সমন্বিত সিস্টেমটি এইচটিএমএল ক্যানভাস উপাদান অনুসরণ করে (উপরের বামে মূল, এক্স-অক্ষটি ডানদিকে নির্দেশ করছে, y- অক্ষটি নীচে নির্দেশ করছে)
ফ্রিডলের জন্য, আমি নীচে বামে একটি পাঠ্য বাক্স যুক্ত করেছি। সেমিকোলন-বিচ্ছিন্ন স্থানাঙ্ক প্রবেশ করান (ডিফল্ট মান একটি উদাহরণ) এবং Go টিপুন।

ফিডল সংস্করণে পার্থক্য

  • পাঠ্যবাক্স
  • ডিফল্ট অ্যানিমেশন পদক্ষেপগুলি 100 এ কমেছে
  • গৌণ বক্ররেখা ডিফল্ট বন্ধ আছে

কোড

<html>
<head>
<style>
span.h{
    display: inline-block;
    text-align: center;
    text-decoration: underline;
    font: bold 1em Arial;
}

input[type="color"]{
    -webkit-appearance: button-bevel;
    vertical-align: -7px;
    width: 21px;
    height: 27px;
}

input[type="color"][disabled]{background: #FFF}

td{position:relative; padding:1px; text-align:center}
table[class] td{text-align:left}
td.t{padding:1px 5px; width:46px;}
table input[type="checkbox"]{visibility:hidden}
tr:hover input[type="checkbox"]{visibility:visible}
</style>
<script type='text/javascript'>
function Bezier(c){
    if(c.length==2) return function(t){return [c[0][0]+t*(c[1][0]-c[0][0]),c[0][1]+t*(c[1][1]-c[0][1])]}
    else return function(t){return Bezier([Bezier(c.slice(0,-1))(t),Bezier(c.slice(1))(t)])(t)}
}

function Bezier2(f1,f2){
    return function(t){return Bezier([f1(t),f2(t)])(t)}
}

//============================================
var c = null
var settings = {'guide':{'show':[true,true,true,true], 'color':['#EEEEEE','#00FF00','#0000FF','#FF00FF'], 'width':[10,1,1,1]}, 'curve':{'show':[true,true,true,true], 'color':['#EEEEEE','#00FF00','#0000FF','#FF00FF'], 'width':[10,3,3,3]}, 'main':{'show':true, 'color':'#FF0000', 'width':10}, 'sample': 100, 'steps':200, 'stepTime':10, 'mode':'Bezier', 'coords':[[0,500],[125,450],[125,0],[500,0]]}
var itv = 0

window.addEventListener('load',function(){
    c = $('c').getContext('2d')
    c.lineCap = 'round'
    c.lineJoin = 'round'
    draw(settings.coords,1)
},true)

function get(k,i){
    var t = settings
    if(k.constructor == Array) k.forEach(function(e){t = t[e]})
    return t.length>i ? t[i] : t.slice(-1)[0]
}

function frame(coords){
    c.strokeStyle = settings.curve.color[0]
    c.lineWidth = settings.guide.width[0]
    c.beginPath()
    c.moveTo.apply(c,coords[0])
    coords.slice(1).forEach(function(e){c.lineTo.apply(c,e)})
    c.stroke()
}

function transf(c){
    var t = []
    c.forEach(function(e){t.push([e[0]+5,e[1]+5])})
    return t
}
//============================================
function drawBezier(coords,t){
    if(t===undefined) t = 1
    coords = transf(coords)
    c.clearRect(0,0,510,510)
    frame(coords)
    c.beginPath()
    c.strokeStyle = settings.main.color
    c.lineWidth = settings.main.width
    c.moveTo.apply(c,coords[0])
    for(var i=0;i<=t*settings.sample;i++) c.lineTo.apply(c,Bezier(coords)(i/settings.sample))
    c.stroke()
}

function animateBezier(coords){
    var s = settings.steps
    var cur = ($('t').value==1 ? ($('t').value=$('T').innerHTML=(0).toFixed(3))*1 : $('t').value*s)+1
    var b = drawBezier(coords,$('t').value*1)
    itv = setInterval(function(){
        $("T").innerHTML = ($("t").value = cur/s).toFixed(3)
        drawBezier(coords,cur++/s,b)
        if(cur>s) clearInterval(itv)
    },settings.stepTime)
}
//============================================
function drawBezier2(coords,t){
    if(t===undefined) t = 1
    c.beginPath()
    c.strokeStyle = get(['curve','color'],coords.length-1)
    c.lineWidth = get(['curve','width'],coords.length-1)
    c.moveTo.apply(c,coords[0])
    for(var i=0;i<=t*100;i++) c.lineTo.apply(c,Bezier(coords)(i/100))
    c.stroke()
}

function drawConstruction(coords,t,B){
    coords = transf(coords)
    if(t===undefined) t = 0.5
    var b = B===undefined ? [[]] : B
    coords.forEach(function(e){b[0].push(function(t){return e})})
    c.clearRect(0,0,510,510)
    frame(coords)
    for(var i=1;i<coords.length;i++){
        if(B===undefined) b.push([])
        with(c){
            for(var j=0;j<coords.length-i;j++){
                if(B===undefined) b[i].push(Bezier2(b[i-1][j],b[i-1][j+1]))
                if(i!=coords.length-1 && get(['curve','show'],i-1) || i==coords.length-1 && settings.main.show){
                    strokeStyle = i==coords.length-1?settings.main.color:get(['curve','color'],i-1)
                    lineWidth = i==coords.length-1?settings.main.width:get(['curve','width'],i-1)
                    beginPath()
                    moveTo.apply(c,b[i][j](0))
                    for(var k=0;k<=t*settings.sample;k++) lineTo.apply(c,b[i][j](k/settings.sample))
                    stroke()
                }
                if(i && i!=coords.length-1 && get(['guide','show'],i)){
                    strokeStyle = i==coords.length-1?settings.main.color:get(['guide','color'],i)
                    lineWidth = i==coords.length-1?settings.main.width:get(['guide','width'],i)
                    beginPath()
                    if(i!=coords.length-1) arc.apply(c,b[i][j](t).concat([settings.curve.width[0]/2,0,2*Math.PI]))
                    stroke()
                }
            }
            if(i && i!=coords.length-1 && get(['guide','show'],i)){
                beginPath()
                moveTo.apply(c,b[i][0](t))
                for(var j=1;j<coords.length-i;j++) lineTo.apply(c,b[i][j](t))
                stroke()
            }
        }
    }
    return b
}

function animateConstruction(coords){
    var s = settings.steps
    var cur = ($('t').value==1 ? ($('t').value=$('T').innerHTML=(0).toFixed(3))*1 : $('t').value*s)+1
    var b = drawConstruction(coords,$('t').value*1)
    itv = setInterval(function(){
        $("T").innerHTML = ($("t").value = cur/s).toFixed(3)
        drawConstruction(coords,cur++/s,b)
        if(cur>s) clearInterval(itv)
    },settings.stepTime)
}
//============================================
function draw(coords,t){clearInterval(itv); return window['draw'+settings.mode](coords,t)}
function animate(coords){clearInterval(itv); return window['animate'+settings.mode](coords);}
//============================================
function $(id){return document.getElementById(id)}
function v(o,p){
    for(var i in o){
        var k = (p||[]).concat([i]).join('-')
        var t
        if((t = o[i].constructor) == Object || t == Array) v(o[i],[k])
        else if(t = $(k)){
            if(t.type=='checkbox') t.checked = o[i]
            else if(t.type=='radio'){
                for(var j=0, t=document.getElementsByName(t.name); j<t.length; j++) if(t[j].value == o[i]){
                    t[j].checked = true
                    break
                }
            }else t.value = o[i]
        }else if(t = $((i==0?'x':'y') + p[0].slice(-1))) t.value = o[i]
    }
}

document.addEventListener('load',function(){
    v(settings)
    $('t').setAttribute('step',1/settings.steps)
    var t = document.getElementsByTagName('input')
    for(i=0;i<t.length;i++) t[i].addEventListener('change',function(){
        var t
        if((t=this.id.split('-')).length > 1){
            var t1 = function(T){
                var t = 'settings'
                T.forEach(function(e){t += '[' + (isNaN(e)?'"'+e+'"':e) +']'})
                eval(t + '=' + (this.type=='text'?this.value:(this.type=='checkbox'?this.checked:'"'+this.value+'"')))
                $(T.join('-')).value = this.value
            }
            t1.call(this,t)
            if(t[0]=='curve' && t[1]=='color' && $('u').checked==true) t1.call(this,['guide'].concat(t.slice(1)))
        }else if(this.id == 'u'){
            for(i=0;t=$('guide-color-'+i);i++){
                t.disabled = this.checked
                t.value = settings.guide.color[i] = this.checked?settings.curve.color[i]:t.value
            }
        }else if(this.id == 't'){
            $('T').innerHTML = (this.value*1).toFixed(3)
            draw(settings.coords,this.value*1)
        }else if(t = /([xy])(\d+)/.exec(this.id)) settings.coords[t[2]*1][t[1]=='x'?0:1] = this.value*1
        else settings[this.id] = this.value
        if(this.id == 'steps') $("t").setAttribute("step",1/settings.steps)
    },true)
},true)
</script>
</head>
<body>
<canvas style='float:left' width='510' height='510' id='c'>
</canvas>
<div style='padding-left:550px; font-family:Arial'>
<span class='h' style='width:123px'>Control Points</span><br />
(<input type='text' id='x0' size='3' maxlength='3' />,<input type='text' id='y0' size='3' maxlength='3' />)<br />
(<input type='text' id='x1' size='3' maxlength='3' />,<input type='text' id='y1' size='3' maxlength='3' />)<br />
(<input type='text' id='x2' size='3' maxlength='3' />,<input type='text' id='y2' size='3' maxlength='3' />)<br />
(<input type='text' id='x3' size='3' maxlength='3' />,<input type='text' id='y3' size='3' maxlength='3' />)<br /><br />
<span class='h' style='width:200px'>Appearance</span><br />
<span style='font-weight:bold'>Guide lines</span><br />
<input type='checkbox' checked='checked' id='u' onchange='' /> Use curve colors<br />
<table style='border-collapse:collapse'>
<tr><td><input type='checkbox' id='guide-show-0' /></td><td><input type='color' id='guide-color-0' disabled='disabled' /></td><td class='t'>Frame</td><td><input type='text' id='guide-width-0' size='2' maxlength='2' /></td></tr>
<tr><td><input type='checkbox' id='guide-show-1' /></td><td><input type='color' id='guide-color-1' disabled='disabled' /></td><td class='t'>1</td><td><input type='text' id='guide-width-1' size='2' maxlength='2' /></td></tr>
<tr><td><input type='checkbox' id='guide-show-2' /></td><td><input type='color' id='guide-color-2' disabled='disabled' /></td><td class='t'>2</td><td><input type='text' id='guide-width-2' size='2' maxlength='2' /></td></tr>
<tr><td><input type='checkbox' id='guide-show-3' /></td><td><input type='color' id='guide-color-3' disabled='disabled' /></td><td class='t'>3</td><td><input type='text' id='guide-width-3' size='2' maxlength='2' /></td></tr>
</table>
<span style='font-weight:bold'>Curves</span>
<table style='border-collapse:collapse'>
<tr><td><input type='checkbox' id='curve-show-0' /></td><td><input type='color' id='curve-color-0' /></td><td class='t'>1</td><td><input type='text' id='curve-width-0' size='2' maxlength='2' /></td></td></tr>
<tr><td><input type='checkbox' id='curve-show-1' /></td><td><input type='color' id='curve-color-1' /></td><td class='t'>2</td><td><input type='text' id='curve-width-1' size='2' maxlength='2' /></td></td></tr>
<tr><td><input type='checkbox' id='curve-show-2' /></td><td><input type='color' id='curve-color-2' /></td><td class='t'>3</td><td><input type='text' id='curve-width-2' size='2' maxlength='2' /></td></td></tr>
<tr><td><input type='checkbox' id='curve-show-3' /></td><td><input type='color' id='curve-color-3' /></td><td class='t'>4</td><td><input type='text' id='curve-width-3' size='2' maxlength='2' /></td></td></tr>
<tr><td><input type='checkbox' id='main-show' /></td><td><input type='color' id='main-color' /></td><td class='t'>Main</td><td><input type='text' id='main-width' size='2' maxlength='2' /></td></td></tr>
</table><br />
<span class='h' style='width:300px'>Graphing & Animation</span><br />
<table class>
<tr><td>Sample points:</td><td><input type='text' id='sample' /></td></tr>
<tr><td>Animation steps:</td><td><input type='text' id='steps' /></td></tr>
<tr><td>Step time:</td><td><input type='text' id='stepTime' />ms</td></tr>
</table>
<div style='position:absolute; top:526px; left:8px; width:510px; height:100px;'>
<input type='range' id='t' max='1' min='0' style='width:450px' value='1' />&nbsp;&nbsp;&nbsp;<span id='T' style='vertical-align: 6px'>1.000</span><br />
<input type='button' onclick='draw(settings.coords,$("t").value*1)' value='Draw' /><input type='button' onclick='animate(settings.coords)' value='Animate' />
<input type='radio' id='mode' name='mode' value='Bezier' />Basic Mode <input type='radio' id='mode' name='mode' value='Construction' />Construction Mode
</div>
</body>
</html>

আপনার এই jsfiddle সামঞ্জস্য করা উচিত যাতে এটি সহজেই পরীক্ষা করা যায়। ভাল সমাধান, যদিও আমি ক্রোমে নিয়ন্ত্রণ পয়েন্টগুলি সেট করতে পারি নি।
SztupY

@SztupY যোগ করা হয়েছে বেহালার
TwiNight

6

পার্ল + পার্লম্যাগিক

use strict;
use Image::Magick;

sub point
{
    my ($image, $f, $x, $y, $r) = @_;
    $image->Draw(fill => $f, primitive => 'circle', points => $x . ',' . $y . ',' . ($x + $r) . ',' . $y);
}

sub line
{
    my ($image, $f, $x1, $y1, $x2, $y2, $w) = @_;
    $image->Draw(fill => 'transparent', stroke => $f, primitive => 'line', strokewidth => $w, points => "$x1,$y1,$x2,$y2");
}

sub colorize
{
    my $i = shift;
    return ((sin($i * 6) + 0.5) * 255) . ',' . ((sin($i * 6 + 2) + 0.5) * 255) . ',' . ((sin($i * 6 + 4) + 0.5) * 255);
}

sub eval_bezier
{
    my $p = shift;
    my @x = @_;
    my @y;
    for my $i (0 .. $#x - 1)
    {
        $y[$i] = $x[$i] * (1 - $p) + $x[$i + 1] * $p;
    }
    return @y;
}

sub render_bezier
{
    my (%args) = @_;
    my $seq = $args{sequence};
    for my $q (0 .. $args{frames} - 1)
    {
        my $p = $q / ($args{frames} - 1);
        my @x = @{$args{xpoints}};
        my @y = @{$args{ypoints}};
        my $amt = @x;
        my $image = Image::Magick->new(size => $args{size});
        $image->ReadImage('xc:black');
        for my $i (0 .. $amt - 1)
        {
            for my $j (0 .. $#x - 1)
            {
                line($image, 'rgba(' . (colorize $i / $amt). ', 0.5)', $x[$j], $y[$j], $x[$j+1], $y[$j+1], 4 * 0.88 ** $i)
            }
            for my $j (0 .. $#x)
            {
                point($image, 'rgba(' . (colorize $i / $amt). ', 1.0)', $x[$j], $y[$j], 4 * 0.88 ** $i);
            }
            @x = eval_bezier $p, @x;
            @y = eval_bezier $p, @y;
        }
        my ($ox, $oy) = ($x[0], $y[0]);
        for my $q (0 .. $q)
        {
            my $p = $q / ($args{frames} - 1);
            my @x = @{$args{xpoints}};
            my @y = @{$args{ypoints}};
            for (0 .. $amt - 2)
            {
                @x = eval_bezier $p, @x;
                @y = eval_bezier $p, @y;
            }
            line($image, 'rgba(255, 255, 255, 1.0)', $x[0], $y[0], $ox, $oy, 2);
            ($ox, $oy) = ($x[0], $y[0]);
        }
        push @$seq, $image;
    }
}

my @x = (10,190,40,190);
my @y = (190,30,10,110);

my $gif = Image::Magick->new;
render_bezier(xpoints => \@x, ypoints => \@y, sequence => $gif, size => '200x200', frames => 70);
$gif->Write(filename => 'output.gif');

আউটপুট উদাহরণ:

অন্যান্য ফলাফলগুলি এই ইমগুর অ্যালবামে দেখা যাবে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.