<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.linuxformat.ru/wiki/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki.linuxformat.ru/wiki/index.php?action=history&amp;feed=atom&amp;title=LXF133%3APython</id>
		<title>LXF133:Python - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.linuxformat.ru/wiki/index.php?action=history&amp;feed=atom&amp;title=LXF133%3APython"/>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF133:Python&amp;action=history"/>
		<updated>2026-05-13T03:04:16Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/index.php?title=LXF133:Python&amp;diff=12415&amp;oldid=prev</id>
		<title>Crazy Rebel: викификация, оформление, иллюстрация</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF133:Python&amp;diff=12415&amp;oldid=prev"/>
				<updated>2011-07-19T09:40:56Z</updated>
		
		<summary type="html">&lt;p&gt;викификация, оформление, иллюстрация&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;'''Python''' Ре­аль­ные про­ек­ты, от­та­чи­ваю­щие на­вы­ки ха­ке­ра&lt;br /&gt;
&lt;br /&gt;
==''Python'': Кох и его снежинка==&lt;br /&gt;
&lt;br /&gt;
: '''Ник Вейч''' уп­раж­ня­ет­ся в ма­те­ма­ти­ке, со­че­тая тео­ре­му Пи­фа­го­ра, ''Python, Clutter'' и ''Cogls'' и по­лу­чая на вы­хо­де кра­си­вые пу­ши­стые сне­жин­ки Ко­ха.&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Python}}&lt;br /&gt;
&lt;br /&gt;
В про­шлых вы­пусках этой се­рии мы раз­влека­лись с ак­те­ра­ми [actor] и сце­на­ми [scene], под­клю­чив мощь до­полнитель­ных биб­лио­тек ти­па ''GStreamer'' и ''Cairo'', что­бы соз­дать по­боль­ше объ­ек­тов и дви­гать ими, по­ка они не запро­сят по­ща­ды. Те­перь по­ра опять за­нять­ся ак­те­ра­ми, но на сей раз мы не ог­раничим­ся нуд­ны­ми пря­мо­угольника­ми и тек­стом, пре­достав­ляе­мы­ми ''Clutter'' – нет, мы соз­да­дим свои. Для это­го по­тре­бу­ет­ся при­влечь неко­то­рые из при­ми­тив­ных ме­то­дов для управ­ления ле­жа­щи­ми в их осно­ве GL-объ­ек­та­ми – по­рез­вим­ся с ''Cogls''.&lt;br /&gt;
&lt;br /&gt;
Пре­ж­де чем на­чать, оп­ре­де­лим­ся с фор­мой, ко­то­рую примет наш ак­тер. Че­ст­но го­во­ря, основ­ные евк­ли­до­вы фор­мы хоть и по­лез­ны, но уны­лы – да­вай­те соз­да­дим нечто по­ин­те­реснее: снежин­ку Ко­ха!&lt;br /&gt;
&lt;br /&gt;
===Что нам на­до===&lt;br /&gt;
&lt;br /&gt;
Оче­вид­но, пре­ж­де чем на­чать, на­до об­за­вес­тись ''Python’''ом и его моду­лем ''Clutter''. Оба они дос­туп­ны в ре­по­зи­то­ри­ях ва­ше­го ди­ст­ри­бути­ва, ес­ли ваш ди­ст­ри­бу­тив об­нов­лял­ся хоть раз за по­след­ний год. Обыч­но безо­пас­нее взять па­кет от­ту­да; ну, а са­мый но­вый ис­ход­ный код для ''Clutter'' – на сай­те http://www.clutter-project.org.&lt;br /&gt;
&lt;br /&gt;
===Да бу­дет снег!===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF133_80_1.jpg|300px]] Здесь по­ка­за­ны пер­вая, вто­рая и де­вя­тая ите­ра­ции сне­жин­ки Ко­ха. Да­лее раз­ни­цу уже не раз­гля­деть.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Снежин­ка (или кри­вая) Ко­ха – это вид фрак­та­ла. Стро­ят­ся фракта­лы, как пра­ви­ло, про­це­дур­ным спо­со­бом, ко­то­рый на-ура адапти­ру­ет­ся ком­пь­ю­те­ра­ми. Уве­рен, что по­пыт­ки по­стро­ить по­добные шту­ки несколь­ки­ми стро­ка­ми на язы­ке ''Basic, Pascal'' или че­му там сей­час де­тей учат (в мое вре­мя это бы­ли ''Algol'' и ''Fortran'') за­няли нема­ло уро­ков ин­фор­ма­ти­ки.&lt;br /&gt;
&lt;br /&gt;
Основ­ная кон­цеп­ция про­ста. Бе­рет­ся рав­но­сто­ронний треугольник. За­тем по­сре­ди ка­ж­дой сто­ро­ны стро­ит­ся еще по одно­му рав­но­сто­роннему тре­угольнику, со сто­ро­ной втрое мень­ше, чем у ис­ход­но­го. Этот шаг по­вто­ря­ет­ся до тех пор, по­ка не на­доест. На ри­сун­ке по­ка­за­но, что по­лу­ча­ет­ся по­сле нескольких ите­ра­ций.&lt;br /&gt;
&lt;br /&gt;
По некой при­чине эта за­да­ча обыч­но ре­ша­ет­ся при­менением ре­кур­сив­но­го ал­го­рит­ма, вы­зы­ваю­ще­го са­мо­го се­бя. Оно, конечно, ум­но и изящ­но, но да­ле­ко от идеа­ла. Ма­ло то­го, что ал­горитм тру­ден в понимании; он еще и ужас­но про­жор­лив. К то­му же мож­но на­ткнуть­ся на ли­мит ко­ли­че­ства ре­кур­сий: ''Python'' ко­режит при мыс­ли о до­бав­лении в стек лишнего об­ра­щения к функции. По умол­чанию ''Python'' раз­ре­ша­ет толь­ко 1000 уровней ре­курсии, и хо­тя уста­нов­кой зна­чений систем­ных пе­ре­мен­ных пре­дел мож­но рас­ши­рить, от­дель­ные плат­фор­мы за­да­ют же­ст­кое ог­раничение.&lt;br /&gt;
&lt;br /&gt;
Для на­ше­го ал­го­рит­ма Ко­ха мы возь­мем менее эф­фектный, но бо­лее эф­фек­тив­ный под­ход – на­деж­ный и дру­же­любный к про­цес­со­ру (важ­ность это­го про­явит­ся поз­же). По­про­сту, мы начнем со спи­ска из трех то­чек, ко­то­рые об­ра­зу­ют бо­лее-менее пра­виль­ный тре­угольник. В цик­ле бу­дем про­смат­ри­вать спи­сок и встав­лять три точ­ки ме­ж­ду ка­ж­дой па­рой то­чек (не забы­вая про па­ру, со­стоя­щую из пер­вой и по­следней то­чек). Та­ким об­ра­зом, ка­ж­дый про­ход цик­ла фор­ми­ру­ет но­вый уро­вень фракта­ла. Это про­сто, и при­мер­но на­по­ло­ви­ну бы­ст­рее ре­кур­сив­ного ре­шения:&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF133_81_1.jpg|300px]] Вот так мы вы­числя­ем, ку­да пе­ре­меща­ют­ся точ­ки.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 def generatekoch(depth=4):&lt;br /&gt;
    sqrtof3=1.7320508075688772&lt;br /&gt;
    pointlist=[(0,50),(75,180),(150,50)] # более-менее равносторонний треугольник&lt;br /&gt;
    for i in range(depth):&lt;br /&gt;
       newlist=[]&lt;br /&gt;
       for p in range(len(pointlist)):&lt;br /&gt;
         x1=pointlist[p][0]&lt;br /&gt;
         y1=pointlist[p][1]&lt;br /&gt;
         if p==len(pointlist)-1:&lt;br /&gt;
            x5=pointlist[0][0]&lt;br /&gt;
            y5=pointlist[0][1]&lt;br /&gt;
         else:&lt;br /&gt;
            x5=pointlist[p+1][0]&lt;br /&gt;
            y5=pointlist[p+1][1]&lt;br /&gt;
            dx=x5-x1&lt;br /&gt;
            dy=y5-y1&lt;br /&gt;
            x2=x1+(dx/3.0)&lt;br /&gt;
            y2=y1+(dy/3.0)&lt;br /&gt;
            x4=x1+(2*dx/3.0)&lt;br /&gt;
            y4=y1+(2*dy/3.0)&lt;br /&gt;
            x3=(x1+x5)/2 + (sqrtof3 * (y1-y5))/6 #см. диаграмму&lt;br /&gt;
            y3=(y1+y5)/2 + (sqrtof3 * (x5-x1))/6&lt;br /&gt;
            newlist.append((x1,y1))&lt;br /&gt;
            newlist.append((x2,y2))&lt;br /&gt;
            newlist.append((x3,y3))&lt;br /&gt;
            newlist.append((x4,y4))&lt;br /&gt;
            #точка 5 уже в списке&lt;br /&gt;
        pointlist = newlist&lt;br /&gt;
    return pointlist&lt;br /&gt;
 if __name__ == “__main__”:&lt;br /&gt;
    list=generatekoch(3)&lt;br /&gt;
    print list&lt;br /&gt;
&amp;lt;/source&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
Пе­ре­мен­ные внут­ри цик­ла со­от­вет­ству­ют пя­ти точ­кам на новых от­рез­ках. Пер­вая и по­след­няя – это те, что бе­рут­ся из ис­ходно­го спи­ска. Осталь­ные три на­до вы­чис­лить. Вто­рая и чет­вер­тая ле­жат на од­ной тре­ти и двух тре­тях от­рез­ка, со­еди­няю­ще­го ис­ходные точ­ки, и их ко­ор­ди­на­ты най­ти неслож­но. Тре­тья точ­ка – верши­на но­во­го тре­угольника, ко­то­рую на­до вы­чис­лить. К сча­стью, тео­ре­ма Пи­фа­го­ра для рав­но­сто­ронних тре­угольников весь­ма упро­ща­ет­ся, и все, что нуж­но вы­чис­лить – это квад­рат­ный ко­рень из 3; его мож­но стя­нуть из биб­лио­те­ки ''math'' (мо­же­те и са­ми написать под­хо­дя­щее при­бли­жение). Ес­ли вас ин­те­ре­су­ет ма­те­ма­ти­ка, вспомните, что пра­виль­ный тре­угольник – это два пря­мо­уголь­ных тре­угольника, при­став­лен­ных друг к дру­гу. За де­таль­ной кар­тиной об­ра­ти­тесь к диа­грам­ме.&lt;br /&gt;
&lt;br /&gt;
Здесь мы ис­поль­зо­ва­ли в ка­че­стве ите­ра­то­ра цикл '''for''', а не список: так про­ще ра­бо­тать с па­рой эле­мен­тов. Мы фор­ми­ру­ем но­вый спи­сок то­чек, а не встав­ля­ем точ­ки в ста­рый, по­сколь­ку при этом, кро­ме все­го про­че­го, пор­тит­ся счет­чик цик­ла.&lt;br /&gt;
&lt;br /&gt;
При та­кой генера­ции снежин­ки есть неболь­шой под­вод­ный ка­мень: фор­му­лы пред­по­ла­га­ют, что точ­ки ис­ход­но­го цик­ла распо­ло­же­ны по ча­со­вой стрел­ке, ина­че кри­вая бу­дет во­гну­той (при этом то­же, кста­ти, по­лу­ча­ет­ся кра­си­вый ри­су­нок).&lt;br /&gt;
&lt;br /&gt;
===Соз­дание ак­те­ров===&lt;br /&gt;
&lt;br /&gt;
Те­перь мы зна­ем, что со­бра­лись ри­со­вать, и мож­но на­чи­нать строить ак­те­ра. В ''Clutter'' есть ме­та­класс для ак­те­ров, и мы ис­поль­зуем его как шаб­лон. То есть, ниче­го не за­пол­няя, мож­но сде­лать новый класс на осно­ве '''clutter.Actor''', и он уже унас­ле­ду­ет мно­же­ство ме­то­дов и свойств.&lt;br /&gt;
&lt;br /&gt;
Объ­ек­ты ''Clutter'' и са­ми унас­ле­до­ва­ны от ''GObject'', ко­то­рый явля­ет­ся ча­стью ''GLib'' от Gnome Foundation, об­шир­ной биб­лио­те­ки кросс-плат­фор­мен­ных струк­тур дан­ных (не пу­тай­те ее с ''Glibc''!). Это по­на­до­бит­ся нам в дальней­шем – мы прихватим несколько кусков из ''GLib'', что­бы наш код за­ра­бо­тал. А по­ка про­сто постро­им ак­те­ра-тре­угольника. От­крой­те тер­ми­нал, вве­ди­те ''python'' для за­пуска ''Python'' в ин­те­рак­тив­ном ре­жи­ме, и вве­ди­те сле­дующее (ес­ли вам лень, ско­пи­руй­те и вставь­те со­дер­жи­мое листинга с '''LXFDVD'''):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; import gobject&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; import clutter&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; from clutter import cogl&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; class Triangle (clutter.Actor):&lt;br /&gt;
 ... def __init__ (self):&lt;br /&gt;
 ... clutter.Actor.__init__(self)&lt;br /&gt;
 ... self._color = clutter.Color(255,255,255,255)&lt;br /&gt;
 ... def do_paint (self):&lt;br /&gt;
 ... (x1, y1, x2, y2) = self.get_allocation_box()&lt;br /&gt;
 ... width=x2-x1&lt;br /&gt;
 ... height=y2-y1&lt;br /&gt;
 ... cogl.path_move_to(width / 2, 0)&lt;br /&gt;
 ... cogl.path_line_to(width, height)&lt;br /&gt;
 ... cogl.path_line_to(0, height)&lt;br /&gt;
 ... cogl.path_line_to(width / 2, 0)&lt;br /&gt;
 ... cogl.path_close()&lt;br /&gt;
 ... cogl.set_source_color(self._color)&lt;br /&gt;
 ... cogl.path_fill()&lt;br /&gt;
 ...&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; gobject.type_register(Triangle)&lt;br /&gt;
 &amp;lt;class ‘__main__.Triangle’&amp;gt;&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вме­сте с биб­лио­те­кой ''Clutter'' мы так­же им­пор­ти­ро­ва­ли ''gobject'' и, осо­бен­но, биб­лио­те­ку ''cogl''. По­след­няя про­сто уко­ротит про­стран­ство имен (вме­сто то­го, что­бы пи­сать '''clutter.cogl.path_move_to''', мож­но опустить пер­вый ''clutter''). ''GObject'' необхо­дим не толь­ко для до­бав­ления свойств и сиг­на­лов, но так­же для ре­ги­ст­ра­ции ти­па объ­ек­та, ко­то­рая тре­бу­ет­ся в ''Clutter''. Можно ви­деть, что мы сде­ла­ли это сра­зу по­сле соз­дания клас­са – это необ­хо­ди­мо про­из­ве­сти до соз­дания ка­ких-ли­бо эле­мен­тов ''Triangle''.&lt;br /&gt;
&lt;br /&gt;
В са­мом клас­се мы оп­ре­де­ли­ли, как обыч­но, ме­тод '''__init__'''. Ме­та­класс '''Actor''' име­ет свой ме­тод '''init''', но мы пе­ре­запи­са­ли его, что­бы до­ба­вить но­вую функ­цио­наль­ность (в на­шем слу­чае это про­сто уста­нов­ка пе­ре­мен­ной цве­та). Од­на­ко мы все-та­ки мо­жем вы­звать имев­ший­ся по умол­чанию ме­тод '''__init__''', яв­ным об­разом; так мы сва­лим на ''Clutter'' ряд обыч­ных для него ве­щей, с ко­торы­ми нам неохо­та во­зить­ся са­мим.&lt;br /&gt;
&lt;br /&gt;
Ме­тод '''paint''' очень ва­жен: он-то и ис­поль­зу­ет функ­ции из ''Cogl''. Ка­ж­дый ак­тер име­ет ме­тод '''paint''', ко­то­рый вы­зы­ва­ет­ся вся­кий раз, когда нуж­но от­ри­со­вать объ­ект. Этот ме­тод вы­зы­вает­ся са­мим ''Clutter'', и мо­жет вы­зы­вать­ся мно­же­ство раз, на­при­мер, при анима­ции.&lt;br /&gt;
&lt;br /&gt;
Коман­ды ри­со­вания про­зрач­ны для понимания. Пред­ставь­те, что у вас есть пе­ро – его нуж­но по­местить в на­чаль­ную по­зи­цию, а за­тем вести линии к раз­ным точ­кам. Ме­тод '''path_close''' объ­е­диня­ет пер­вую и по­след­нюю точ­ки для за­мы­кания кон­ту­ра, что обяза­тель­но при за­лив­ке. До­полнитель­ных команд ри­со­вания пол­но (у мно­гих есть аб­со­лют­ные и от­но­си­тель­ные вер­сии), и до­ку­мента­ция для при­ми­ти­вов доступ­на на сай­те ''Clutter'': http://clutter-project.org/docs/cogl/stable/cogl-Primitives.html. Конеч­но, это доку­мен­та­ция для ''C'', но ра­зо­брать­ся в ра­бо­те ме­то­дов там со­всем неслож­но.&lt;br /&gt;
&lt;br /&gt;
===Чу­де­са ри­со­вания===&lt;br /&gt;
&lt;br /&gt;
И по­следний ма­ги­че­ский трюк в этом ко­де – в на­ча­ле ме­то­да '''paint'''. Вы­зов '''get_allocation_box''' ис­поль­зу­ет один из унас­ле­дован­ных ме­то­дов '''Actor''', что­бы уз­нать раз­мер от­ри­со­ванн­но­го акте­ра, ко­то­рый воз­вра­ща­ет две точ­ки, за­даю­щие пре­де­лы об­ласти ри­со­вания. На дан­ный мо­мент не сто­ит бес­по­ко­ить­ся о раз­ме­ре объ­ек­та – при ка­ж­дом вы­зо­ве ак­тер­ско­го ме­то­да '''set_size()''', разно­об­раз­ные внут­ренние про­це­ду­ры ''Clutter'' по­за­бо­тят­ся об изменении раз­ме­ра ак­те­ра, а раз­мер об­ласти для ри­со­вания по­меня­ет­ся в со­от­вет­ствии с ним.&lt;br /&gt;
&lt;br /&gt;
Те­перь про­тес­ти­ру­ем на­ши тре­уголь­ни­ки, вы­пол­нив обыч­ную ус­та­нов­ку сце­ны и до­ба­вив объ­ек­ты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; stage=clutter.Stage()&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; stage.set_size(400,400)&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; t=Triangle()&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; t.set_size(50,50)&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; stage.add(t)&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; stage.set_color(clutter.Color(0,0,0,255))&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; stage.show_all()&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; tt=Triangle()&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; tt.set_size(100,100)&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; tt.set_position(200,200)&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; stage.add(tt)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Те­перь мож­но соз­да­вать тре­уголь­ни­ки и да­же ани­ми­ро­вать их:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; tt.animate(clutter.EASE_IN_QUAD,2000,’y’,0)&lt;br /&gt;
 &amp;lt;clutter.Animation object at 0x97b334c (ClutterAnimation at 0x98a1990)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Но не все так про­сто, как ка­жет­ся. По­про­бу­ем по­ме­нять цвет на­ше­го тре­уголь­ни­ка, та­ким спо­со­бом:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; tt.set_color(clutter.Color(255,255,0,255))&lt;br /&gt;
 Traceback (most recent call last):&lt;br /&gt;
 File “&amp;lt;stdin&amp;gt;”, line 1, in &amp;lt;module&amp;gt;&lt;br /&gt;
 AttributeError: ‘Triangle’ object has no attribute ‘set_color’&lt;br /&gt;
&lt;br /&gt;
===На­лог на на­след­ст­во===&lt;br /&gt;
&lt;br /&gt;
Функ­цио­наль­ность стан­дарт­но­го ак­те­ра на­сле­ду­ет­ся не пол­ностью. В от­ли­чие от встро­ен­но­го объ­ек­та '''rectangle''', у нас нет ме­то­да для ус­та­нов­ки цве­та соз­дан­но­го на­ми объ­ек­та '''Triangle'''. Для это­го нуж­но до­ба­вить в класс:&lt;br /&gt;
&lt;br /&gt;
 def set_color (self, color):&lt;br /&gt;
 self._color = color&lt;br /&gt;
&lt;br /&gt;
Этот ку­сок ко­да, оче­вид­но, дол­жен быть ча­стью глав­но­го класса, и в этом при­ме­ре он при­ни­ма­ет стан­дарт­ный объ­ект '''clutter.Color()''', хо­тя это мож­но из­ме­нить. Так,при­ме­няя это к на­шей снежин­ке Ко­ха, мы по­лу­чим не­что вро­де сле­дую­ще­го (за­меть­те, что для крат­ко­сти здесь ге­не­ра­тор Ко­ха не по­ка­зан):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 import gobject&lt;br /&gt;
 import clutter&lt;br /&gt;
 from clutter import cogl&lt;br /&gt;
 class Koch (clutter.Actor):&lt;br /&gt;
    “””&lt;br /&gt;
    Актер снежинки Коха&lt;br /&gt;
    имеет дополнительное свойство ‘_iterations’, управляющее глубиной фрактала&lt;br /&gt;
    “””&lt;br /&gt;
   __gtype_name__ = ‘Koch’&lt;br /&gt;
   def __init__ (self):&lt;br /&gt;
    clutter.Actor.__init__(self)&lt;br /&gt;
    self._color = clutter.Color(255,255,255,255)&lt;br /&gt;
    self._iterations = 2&lt;br /&gt;
    self._points=[(0,0),(0,0),(0,0)]&lt;br /&gt;
   def generatekoch(self,dimension):&lt;br /&gt;
    ### см. выше&lt;br /&gt;
    return pointlist&lt;br /&gt;
&lt;br /&gt;
   def set_color (self, color):&lt;br /&gt;
    self._color = color&lt;br /&gt;
   def __paint_shape (self, paint_color):&lt;br /&gt;
    pointlist=self._points&lt;br /&gt;
    cogl.path_move_to(pointlist[0][0], pointlist[0][1])&lt;br /&gt;
    for point in pointlist:&lt;br /&gt;
     cogl.path_line_to(point[0], point[1])&lt;br /&gt;
    cogl.path_close()&lt;br /&gt;
    cogl.set_source_color(paint_color)&lt;br /&gt;
    cogl.path_fill()&lt;br /&gt;
   def do_paint (self):&lt;br /&gt;
    paint_color = self._color&lt;br /&gt;
    real_alpha = self.get_paint_opacity() * paint_color.alpha / 255&lt;br /&gt;
    paint_color.alpha = real_alpha&lt;br /&gt;
    self.__paint_shape(paint_color)&lt;br /&gt;
&lt;br /&gt;
   def set_size (self,width,height):&lt;br /&gt;
    clutter.Actor.set_size(self,width,height)&lt;br /&gt;
    dimension=float(min(width,height))&lt;br /&gt;
    self._points=self.generatekoch(dimension)&lt;br /&gt;
&lt;br /&gt;
   def set_iterations (self,number):&lt;br /&gt;
    self._iterations=number&lt;br /&gt;
    (x,y) = self.get_size()&lt;br /&gt;
    dimension = min(x,y)&lt;br /&gt;
    self._points=self.generatekoch(dimension)&lt;br /&gt;
    self.do_paint()&lt;br /&gt;
 gobject.type_register(Koch)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мож­но ви­деть, что мы храним спи­сок то­чек в ви­де свойства – пе­ре­ри­со­вы­вать кри­вую глу­би­ны во­семь и вы­ше с ну­ля, да еще и несколь­ко раз в се­кун­ду, бы­ло бы очень за­трат­но! Генерация спи­ска вы­зы­ва­ет­ся вся­кий раз, когда из­ме­ня­ет­ся чис­ло ите­раций. Это зна­чит, что обыч­но при уста­нов­ке объ­ек­та точ­ки фор­миру­ют­ся два­ж­ды, пред­по­ла­гая, что ко­ли­че­ство ите­ра­ций, стоя­щее по умол­чанию, из­менено. К со­жа­лению, это не уст­ранить, ес­ли толь­ко вы не хо­ти­те, что­бы «глу­би­на» фрак­та­ла име­ла дей­ствие толь­ко при из­менении раз­ме­ра.&lt;br /&gt;
&lt;br /&gt;
Мы пе­ре­запи­са­ли ме­тод '''set_size''' клас­са '''Actor''', что­бы убе­диться, что в сфор­ми­ро­ван­ных на­ми точ­ках от­ра­жа­ет­ся раз­мер объ­екта, но, тем не менее, все еще необ­хо­ди­мо вы­зы­вать ме­тод '''set_size''' ро­ди­тель­ско­го клас­са, что­бы удо­сто­ве­рить­ся, что бу­фе­ры и прочее об­но­ви­лись.&lt;br /&gt;
&lt;br /&gt;
Что­бы про­де­мон­ст­ри­ро­вать на­ши но­вые фи­гу­ры, вот вам простой генера­тор для тести­ро­вания:&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF133_83_1.jpg|300px]] Вот и сно­ва вы­пал снег — ваш воз­вы­шен­ный код от Linux Format мо­жет соз­да­вать снежин­ки при лю­бой по­го­де.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 import clutter, random&lt;br /&gt;
 from clutterKoch import Koch&lt;br /&gt;
 stage = clutter.Stage()&lt;br /&gt;
 stage.set_size(640, 480)&lt;br /&gt;
 stage.set_color(clutter.Color(0,0,0,255))&lt;br /&gt;
 stage.connect(‘destroy’, clutter.main_quit)&lt;br /&gt;
 for i in range(10):&lt;br /&gt;
    s = Koch()&lt;br /&gt;
    x=random.randint(20,90)&lt;br /&gt;
    s.set_size(x, x)&lt;br /&gt;
    s.set_iterations(6)&lt;br /&gt;
    s.set_color(clutter.Color(200,200,random.randint(200,255),255))&lt;br /&gt;
    z=random.randint(0+x,640-x)&lt;br /&gt;
    zz=random.randint(x,x+200)&lt;br /&gt;
    s.set_position(z,-zz)&lt;br /&gt;
    stage.add(s)&lt;br /&gt;
    s.animate(clutter.EASE_IN_QUAD, 5000,’y’,x+random.randint(480,550),’rotation-angle-y’,random.randint(180,720))&lt;br /&gt;
    stage.show()&lt;br /&gt;
  clutter.main()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При усло­вии, что файл '''Actor''' (в на­шем слу­чае это '''clutterKoch.py''') на­хо­дит­ся в том же ка­та­ло­ге, это мож­но за­пускать и ри­со­вать слу­чай­ные кри­вые. Как вы уви­ди­те, на­ши тво­рения мож­но дви­гать и вра­щать. Для это­го не нуж­но за­но­во фор­ми­ро­вать все точки: на дан­ный мо­мент они яв­ля­ют­ся GL-точ­ка­ми, и об их пра­вильном по­ло­жении по­за­бо­тит­ся ви­део­кар­та.&lt;br /&gt;
&lt;br /&gt;
===Что даль­ше===&lt;br /&gt;
&lt;br /&gt;
''Cogls'' по­ле­зен не толь­ко при ри­со­вании раз­ных форм. Ис­поль­зуя этот ин­тер­фейс к ''OpenGL'', мож­но по­ме­нять мно­же­ство ас­пек­тов ото­бра­жения, вплоть до соз­дания соб­ствен­но­го шей­де­ра. На сайте ''Clutter'' есть мно­го до­ку­мен­та­ции по раз­ным воз­мож­но­стям ''Cogls''. Од­на­ко, как мы отметили ранее, она пред­на­зна­че­на для про­грам­ми­стов на ''C'', и вам при­дет­ся по­тра­тить неко­то­рое вре­мя, чтобы это за­ра­бо­та­ло в ''Python''. Взгляните на http://clutter-project.org/docs/cogl/stable.&lt;br /&gt;
&lt;br /&gt;
Мы так­же небреж­но отнеслись к на­строй­ке на­ше­го '''gobject'''. В сущ­но­сти, все что мы сде­ла­ли – это са­мый минимум, что­бы '''Actor''' за­ра­бо­тал. Тот, кто пра­виль­но об­ра­ща­ет­ся с систе­мой, должен за­ре­ги­ст­ри­ро­вать '''GObject'''’ов­ские свой­ства на­ше­го объ­ек­та, и мож­но да­же до­ба­вить для него соб­ствен­ные сиг­на­лы. '''GObject''' пре­кра­сен, хотя и сло­жноват и мно­го­сло­вен; увы, здесь ма­ло места, что­бы пол­но­стью его раскрыть. Но до­ку­мен­тация ''PyGTK'' со­дер­жит мно­го по­лез­ной ин­фор­ма­ции о '''GObject''', и если вам ин­те­рес­но, зай­ди­те на http://www.pygtk.org/docs/pygobject.&lt;/div&gt;</summary>
		<author><name>Crazy Rebel</name></author>	</entry>

	</feed>