Category:Home (Total 35 items)

≪ 6-10 | 1-5

Categories

Math

原文http://nodebox.net/code/index.php/Math

しばしば、NodeBoxスクリプトのプログラミングをすると、少しの数学が関わる。
流体の動作の、行動の軌跡、内外への緩和、全て数学の定石を必要とする。
多分我々の多くは数学のクラスにおいて注意を払ってないので、このドキュメントは幾つかの有用な数学テクニックを説明する。

Math geometry

2点の座標がある場合に、この2点間の角度(もしくは距離)を知りたいことがある。
もしくは調節された1点があり、角度と距離を基にして2つめの点を知りたい時。
次のmathコマンドは手助けになるかもしれない。
またsineとcosineを基に見付けることも出来る。 http://nodebox.net/code/index.php/Math_trigonometry

2点間の角度

def angle(x0, y0, x1, y1):
    from math import degrees, atan2
    a = degrees( atan2(y1-y0, x1-x0) )
    return a

2点間の距離

ef distance(x0, y0, x1, y1):
    from math import sqrt, pow
    return sqrt(pow(x1-x0, 2) + pow(y1-y0, 2))

距離と角度を基にした点の位置

def coordinates(x0, y0, distance, angle):
    from math import radians, sin, cos
    x1 = x0 + cos(radians(angle)) * distance
    y1 = y0 + sin(radians(angle)) * distance
    return x1, y1

点に関して対称

def reflect(x0, y0, x1, y1, d=1.0, a=180):
    d *= distance(x0, y0, x1, y1)
    a += angle(x0, y0, x1, y1)
    x, y = coordinates(x0, y0, d, a)
    return x, y

これらのコマンドをスクリプト内で使うにはシンプルにこれらをimportする。

from nodebox.geo import angle, distance, coordinates, reflect

いくつかの例:

randomポイントの中心からの方向

x0, y0, r = WIDTH/2, HEIGHT/2, 2

for i in range(5):
    x1 = random(WIDTH)
    y1 = random(HEIGHT)
    oval(x1-r, y1-r, r*2, r*2)
    a = angle(x0, y0, x1, y1)
    transform(CORNER)
    translate(x0, y0)
    rotate(-a)
    arrow(30, 0, 10)
    reset()

x0, y0への軌跡

x0, y0, r = WIDTH/2, HEIGHT/2, 2
oval(x0-r, y0-r, r*2, r*2)

for i in range(10):
    a = 36*i
    x1, y1 = coordinates(x0, y0, 85, a)
    oval(x1-r, y1-r, r*2, r*2)
    line(x0, y0, x1, y1)

円パス上の垂直線: 点と-90度操作したものの角度

path = oval(100, 100, 105, 105)
for t in range(50):
    pt = path.point(float(t) / 50)
    a = angle(pt.x, pt.y, 
        pt.ctrl2.x, pt.ctrl2.y)
    transform(CORNER)
    push()
    translate(pt.x, pt.y)
    rotate(-a+90)
    line(0, 0, 35, 0)
    pop()

時々、オブジェクトの位置やサイズを、お互いに関連づけ、ある種の注文や調和があるような方法で、与えたいことがある。
例えば、サイン波は、動作を記述するのに良い。なぜなら、ゆるやかにin outする。
別の面白い比例した原則は黄金比、3-5-8ルールである。
長い長い時間、回りには美的感覚がある。
その素晴しい事柄は、数学のシリーズ、フィナボッチ配列として表すことができる。

def fib(n):
    if n == 0: return 0
    if n == 1: return 1
    if n >= 2: return fib(n-1) + fib(n-2)

def goldenratio(n, f=4):
    # Returns two proportional numbers whose sum is n.
    f = max(1, min(f, 10))
    n /= float(fib(f+2))
    return n*fib(f+1), n*fib(f)

着色された矩形が黄金比で形成される。

w1, w2 = goldenratio(260)
h1, h2 = goldenratio(260)
b1, b2 = goldenratio(1.0)
b3, b4 = goldenratio(b1)

fill(0, b1/2, b1)
rect(0, 0, w1, h1)

fill(0, b2/2, b2)
rect(w1, 0, w2, h1)

fill(0, b4/2, b4)
rect(0, h1, w1+w2, h2)

x, y = 0, 0
w, h = 260, 260

th = h # top height
bh = 0 # bottom height
for i in range(10):
    th, bh = goldenratio(th)
    v = float(th)/w + 0.3
    fill(0, v/2, v)
    rect(x, y, w, th)
    y += th
    th = bh
  • Comments (Close): 0
  • TrackBack (Close): 0

Color

NodeBoxのcolor()コマンドから返されたColorはいくつかの有用なattributeを持ち、同時に異なる色空間を考えさせる。
例えば、ランダムな色でグリッド線を描画したい時、次のようなコードを使う。:

for i in range(HEIGHT):
  c = color(random(), random(), random())
  stroke(c)
  strokewidth(1)
  line(0, i, WIDTH, i)

しかし、各lineがランダムなstrokeだと、幾つかのlineはさえなく、明るく見える傾向がある。
色を持ち上げるために、異なる色空間に切り替えせず、lineのサチュレーションを簡単に調節できる。
同じ理由から、strokewidthを1の代りに2を使用し、lineをオーバーラッピングさせ、より明るくさせる。

for i in range(HEIGHT):
  c = color(random(), random(), random())
  c.saturation = 1.0
  stroke(c)   
  strokewidth(2)
  line(0, i, WIDTH, i)

Color attributes

color()コマンド(さらに言えばfill()やstroke()コマンド)から返されたColorは、次にattributeを持つ:

color.r: the RGB red component
color.g: the RGB green component
color.b: the RGB blue component
color.a: the alpha component
color.c: the CMYK cyan component
color.m: the CMYK magenta component
color.y: the CMYK yellow component
color.k: the CMYK black component
color.hue: the HSB hue component
color.saturation: the HSB saturation component
color.brightness: the HSB brightness component

これらはスクリプト内でいつでも使用出来、NodeBoxは正確にcolorを計算する。

CMYK output?

出力の為に何の色空間が使われていますか?
スクリプト内でどのようなcolormode()が使用されていても、出力はoutputmode()に追随する。
これは、技術的詳細について心配する必要がないような印刷ドキュメントを働かせる時、それを簡単にし、好きなcolorに焦点を合わせることが出来る。
もっとも、全てのRGBカラーが印刷可能であるわけではないことを覚えておくこと。

Colors are stored in the graphics state

NodeBoxは最後に定義したcolorを覚えており、異なるものを定義するまで、fillやstroke colorが使っているcolorを留める。

Harmonious colors

調和のある、一貫したcolorを作る為のトリックは、完全にランダムにしないで、一定の範囲で制限する。
一般的な落とし穴は、colorを可能なかぎり全て使うことである。
これは、しばしば、一貫したデザインを作らない。

HSBカラーモードはcolorのハーモニーを作るために優秀である。

次のサンプルを考察せよ。:

colormode(HSB)
nofill()
for i in range(10):
  c = color(0.5, random(0.5), random(0.5,1.0))
  stroke(c)
  strokewidth(random(50))
  radius = random(200)
  oval(random(WIDTH), random(HEIGHT), radius, radius)

色相(Hue)はいつも同じ、0.5もしくは180の色相(シアン)である。
彩度(Saturation)と明度(Brightnes)だけが少し変えられる。

これは、いつも青の色を持つことを確実にし、全てフィットする。
彩度(Saturation)は、色褪せて見えるため、0.0から0.5間で制限された。
その上、明度(Brightnes)が0.0から0.5間(50%から100%)で制限されたので、我々はブライトなcolorを得る。
これらの「color range」の素晴しいサポートを持つ colorライブラリを見よ。

画像略

Gradients

NodeBoxにおいて、lineをfor-loopで描画し、各lineの透明度を増大することによって、グラーションを作ることが出来る。
例では、color cの透明度を0.0から1.0に下げた。 (浮動小数点を得る為に、1.0で乗算していることに注意せよ。)

colormode(HSB)
c = color(0.5, 1, 1)
for i in range(HEIGHT):
  c.a = 1.0 * i / HEIGHT
  stroke(c) 
  line(0, i, WIDTH, i)

colorライブラリはより複雑なグラデーションを操縦する、手軽なgradientコマンドを持つ。

  • Comments (Close): 0
  • TrackBack (Close): 0

Fatpath

原文http://www.nodebox.net/code/index.php/Fatpath

Fatpathはパス上の点において数学的処理をする。
本質的に、テキストのパスを加算する。
公式は以下になる。:

p1 + (p2 - p1) * fatness

この機能はテキストの形態に、(マルチプル-マスター フォントのように)細くしたり太くしたり出来、
同様に輪郭を越え、極細、極太フォントを計算出来る、ような機能をもたらす。

Screenshot

下のパスは上二つのパスより計算された。

Restrictions

fatpathはかなり馬鹿である。:
パスはポイントポイントで正確に合わなければならない。そうでないと、アルゴリズムは動かない。
これは(一般的に)、同じフォントファミリーのフォントのみ使用でき、その時でさえ、文字がマッチする保証は何もない、ことを意味する。
カーブを持った文字は特に厄介である。
特別なボタン(lettersthatwork)は、与えられたフォントにどの文字を使用できるかを示す。

Download

  • Comments (Close): 0
  • TrackBack (Close): 0

L-system

L-system(Lindenmayer system)は、成長過程をモデルする為に使用される、ルールとシンボルのセットである。
http://en.wikipedia.org/wiki/L-system
L-systemは自然では再帰的(recursive in nature)である。これは、全体が「全体と同様な小さなパーツ」で作られることを意味する。
例えば、一本の木は、小さな枝の成長からできた大きな枝だと言える。
それぞれの小さな枝はまた成長し、小さな枝をつけたりする。
一つの枝がどのようになるかを知っていれば、我々は木全体をモデルすることが出来る。
また、再帰ルールに基ずくエレガントは環境は、ContextFreeを見よ。
http://www.contextfreeart.org/

NodeBoxのL-systemライブラリは再帰とルールセットにより簡単に動作する。
Frederik De Bleser と Mark Meyer によるコードを基にしている。
(ギャラリーにあるDryadとMark Meyer's L-systemを見よ。)
http://www.nodebox.net/code/index.php/Dryad http://www.nodebox.net/code/index.php/Mark_Meyer_|_L-system

Download

Documentation

How to get the library up and running

NodeBoxのスクリプトが探すことが出来るように、lsystemライブラリフォルダをスクリプトと同じフォルダに入れる。
また、~/Library/Application Support/NodeBox/に置くことも出来る。

lsystem = ximport("lsystem")

Creating a new L-system

create(angle=20, segmentlength=40, rules={}, root=None)

create()コマンドは新しいL-systemオブジェクトを返す。オブジェクトは与えられたx, yポジションからキャンバス上を育つ。
オブジェクトはプロパティを持つ。

  • lsystem.angle: +と-ルール シンボルに使用される回転のアングル
  • lsystem.segmentlength: 単セグメントの長さ、もしくはサイズ
  • lsystem.decrease: システムの成長におけるセグメントの減少量(0.7 がデフォルト)
  • lsystem.threshold: この値より小さくなった場合にセグメントの描画を停止する(3.0 がデフォルト)
  • lsystem.root: 成長の為の最初のルール (ルール key "1" がデフォルト)
  • lsystem.rules: DNAシステムの辞書のルール
  • lsystem.commands: カスタムコマンド シンボルの辞書
  • lsystem.cost: 単セグメントの描画にかかる時間 (0.25 がデフォルト)

L-systemオブジェクトは描画の為の2つのメソッドを持つ。

lsystem.draw(x, y, generation, time=None, ease=None)

lsystem.segment(length, generation, time=None, id=None)

lsystem.draw()メソッドは与えられた位置での成長パターンを描画する。
generation(世代)パラメータは、どれだけ深くパターンが続くかを決定する。
我々の「木は大きな枝である」の例題では、世代 3 は以下を意味する。:
一本の枝(1)を描き、枝(1)を伸ばしたものが、全て育成し枝々(3)になる。
たくさんのセグメントが世代が終るまで、もしくはlsystem.thresholdより小くなるまで育成する。

timeパラメータはアニメーション内で使用出来る。
セグメントが描画されると、lsystem.costと等しい少しの時間を少しずつ崩す。
アニメーション内でゼロからtimeが始まり、徐々に増大すると、セグメントはより大きくなり、それらのより大きなものは描画される。
(costを支払うより多くのtimeがあるので)

2番目のオプションパラメータ easeはアングルの回転を進展させる為に使用出来る。
通常は4から20の数値で、つぼみが開く(unfold)成長パターンを使用できる。

lsystem.segment()メソッドは単セグメントを描画するためのコードを含む。
あなた自身が(葉のような)カスタムセグメントを欲しい時、このメソッドを再定義する必要がある。
後に書くであろう。

lsystem.segments(generation, time=None)

lsystem.duration(generation)

lsystem.segments()メソッドは与えられた世代数(そして時間)を育てる為のセグメントの数を返す。

lsystem.duration()全てのセグメントを描画するのに必要なトータルの時間を計算する。
現在のlsystem.costを基にする。

Growing rules

L-systemの形は、ルールの設定に依存する。
ルールは事前定義されたsymbolsの文字列であり、それぞれが変化コマンドを表す。(scale()やrotate()のように)
それで、一つのルールはNodeBoxコードの断片を表すDNAストリングのような小片である。 以下全てのシンボルである。:

  • F : systemがここにセグメントを描画する(矩形がデフォルト)
  • f : 描画せずに次のポジションへ移動する
  • + : lsystem.angleにより反時計回りに回転する
  • _ : lsystem.angleにより時計回りに回転する
  • | : 180度回転する
  • [ : push()コマンドのように動作する。サブブランチの開始
  • ] : pop()コマンドのように動作する。サブブランチの終了
  • ! : 回転アングルを反転する
  • ( : 回転アングルを110%増加する
  • ) : 回転アングルを90%に減少する
  • < : セグメントの長さを110%増加
  • > : セグメントの長さを90%減少

いくつかsymbolを試してみよう!
ルールはシンプルだ:

3つのセグメントを描画する。

tree = lsystem.create()
tree.rules["1"] = "FFF" 
tree.draw(50, 150, 1)

2つのセグメントを描画し、時計回りに回転させ、別のセグメントを描画する。

tree = lsystem.create()
tree.rules["1"] = "FF-F" 
tree.draw(50, 150, 1)

ルール:( 2つのセグメントを描画し、時計回りに回転する)を描画する。
我々がより多くの世代において生産出来るようにシンボル文字列からルールのキーを参照するように注意せよ。
これが再帰の典型的な例である。
http://en.wikipedia.org/wiki/Recursion

tree = lsystem.create()
tree.rules["1"] = "FF-1" 
tree.draw(50, 150, 6)

再帰のポイントで枝が生成され、反時計回りに回転し、セグメントを描画、反時計回りに回転、別のセグメントを描画。

tree = lsystem.create()
tree.rules["1"] = "FF-[1]++F+F" 
tree.draw(50, 150, 6)

枝でより多く再帰する

tree = lsystem.create()
tree.rules["1"] = "FF-[1]++F+F+1" 
tree.draw(50, 150, 6)

独立した枝々でより複雑なルールセット

tree = lsystem.create(segmentlength=20) tree.rules = { "1" : "FF[-2]3[+3]", "2" : "FF+F-F-F[FFF3][+3]-F-F3", "3" : "FF-F+F+F[2][-2]+F+F2" } tree.draw(50, 150, 6)

Custom segments

デフォルトでは、systemはセグメントの為に線により結合された矩形である。
新しい外観を得るために、自分でセグメントコマンドを書かなければならない。
デフォルトのセグメントコマンドはこのようになる。:

def segment(self, length, generation, time=None, id=None):
    push()
    line(0, 0, 0, -length)
    scale(0.65)
    rect(-length/2, -length, length, length)
    pop()

L-systemは、セグメントからセグメントへ移動する為にcorner-mode translate()コマンドを使う。

つづく

  • Comments (Close): 0
  • TrackBack (Close): 0

Animation

原文http://www.nodebox.net/code/index.php/Animation

NodeBoxはPDFや画像書き出すだけでなく、アニメーションも操作し、QuickTimeムービーで書き出せる。
描画と同じ構文を使い、スクリプトをアニメーションに変えることが出来、それば素晴しく、活気のあることだ。

The speed(), setup(), and draw() commands

アニメーションを動かす為に3つの事が必要である。:

  • speed(): speed()コマンドはアニメーションの毎秒毎のフレーム数(frames per second, fps)を示す。注意点として、この値は最大値であるということ: より作業が必要な大きなアニメーションでは設定値より遅く動く。
  • setup(): setup()定義により、global変数を宣言したり、それらを初期化する。
  • draw(): draw()定義により、実際の描画をする。

Templating(Commands)チュートリアルより、Commandsの定義についてあなたは既に少ししっているかもしれない。

setup()コマンドはアニメーションの開始において一度だけ実行される、そしてdraw()はアニメーション内の各フレームもしくは各ステップで実行される。
上のサンプルを見なさい。(画像のため省略)
setup()の定義で何をしてるかというと、frameと命名したglobal変数を宣言している。これは後でdraw()において使われ、キャンバス上にレンダリングされたアニメーションフレームのトラックを保持する。
setup()とdraw()がコミュニケート出来ず、また共有できないので変数はglobalにしなければならない。

draw()の定義について吟味する。
それは、アニメーションスクリプトの典型例である。
draw()コマンドがNodeBoxに呼び出され、アニメーションのフレーム毎にレンダリングする。
上の例では、draw()の定義は基本的は4つのことをする。

  • frame変数を1つ増やす。(これは、私のフレームカウンタである。)
  • 背景を描画する為、色の付いたrectangleを使う。
  • 30度回転したcurveを描画する。
  • curveが流動的に歪ませるためにmathのsin()ファンクションを使う。

Fluid movement

draw()定義内の数学的なsineファンクションに注意せよ。 sineは、0.0から1.0(そして0.0へ戻る)の値をもたらす振動ファンクションで、直線的ではない。
0もしくは1にアプローチすると、ゆっくり向う。
これはアニメーションがゆるやかにin outするのに有用である。 sin()ファンクションを使うには、radians()ファンクションとともにPythonのmathパッケージをインポートする。
(sineは円周率PIと同じくラジアンと共に動作する)
上の例では、sineファンクションをラジアンでframe変数に与える。
そして、各curveで異なる数を乗算する。
各カーブは緩やかな流体歪みのvectorを与える。

sineファンクションは通常このように呼び出す。

from math import sin, radians
ease = sin(radians(x)) * y

Tips for speed optimization

  • アニメーションの中で多数のlinesを使う計画であるなら、lineto()やmoveto()の単体のパスをグループ化する。 単体の大きなパスは沢山の小さいパスより高速にレンダリングされる。 全てのラインはしかしながら、同じcolorとwidthである。
  • アニメーションの中で多数のtextを使う計画であるなら、setup()コマンドでtextpath()バージョンのキャッシュを作成し、draw()コマンドにおいて、text()を連続的に呼び出して描画する代りにtranslate()を使う。
  • 必要な速さにspeed()コマンドを調整せよ。NodeBoxがあまりにアップデートを試みてしまう為、できるだけ高く設定することが、欠点となってしまうことがある。
  • 必要な大きさにキャンパスのサイズをsize()で調節せよ。より小さいスクリーンならリフレッシュも少ないことを意味する。

Exporting as a Quicktime movie

アニメーションをQuicktimeムービーとして書き出すことができる。
NodeBoxのメニューからExport as Quicktime Movie...を選ぶか、cmd+shif+eを押す。
フレームの数とfpsを指定出来る。

NodeBoxのQuicktime機能は、Bob IppolitoによるPyQTSequenceをベースにしている。
http://undefined.org/python/

ムービは圧縮されないので巨大なサイズになる。
Quicktime Pro等で圧縮することが出来る。

…これで、あなたはwebサイトに出すムービーを持った!

  • Comments (Close): 0
  • TrackBack (Close): 0

Category:Home (Total 35 items)

≪ 6-10 | 1-5

Tutorial
Library
Syndicate this site

RSS 1.0 Feed

Return to page top