Деян Йосифов

 Personal Website & Blog

Имплементация на Shooter Game Navigation като Plug-in за Google Sketch Up

Written By: Деян - Feb• 15•13

sketchupВероятно, който се е занимавал с моделиране на 3д обекти, под някаква форма се е сблъсквал с програмата Google Sketch Up. Личното ми мнение е, че това е една страхотна програма, изключително лека (зарежда със скоростта на Notepad), а в същото време дава доста големи възможности за свободно моделиране на всевъзможни форми и като цяло поне за мен за създаването на малки по размер 3д обекти и дизайни, както и за концептуални модели, програмата е наистина безценна.
Още повече се запалих по тази програма преди няколко години, когато разбрах, че за Sketch Up си има една цяла общност от ентусиасти (Sketchucation.com), които пишат и публикуват безплатни плъгини (направени за собствени нужди или по поръчка на някой пишещ във форума), които плъгини добавени към програмата вече могат да я направят наистина мощно средство за лесно създаване на модели за дизайн и архитектура например.

Така след като известно време ползвах различни плъгини към програмата, в един момент реших и аз да се пробвам да се науча и да пиша такива. И това се оказа далеч не толкова трудна задача – макар и никога дотогава да не бях и чувал за Ruby, в интернет има изключително удобна и подробна документация на Sketch Up Ruby API и след прочитането на една малка книжка за основите на езика, аз вече можех спокойно да пиша първите си плъгини.

Цялата идея е да се напише един файл с разширение .rb, който да се сложи в инсталационната директория на програмата в папка Plugins. При зареждане на Sketch Up, програмата  компилира всички файлове в папка Plugins, и те вече стават активни в текущо отворения прозорец на Sketch Up. Тук е момента и да кажа, че ако си свалите стотина Plugin-a в папката, то вече Sketch Up далеч няма да зарежда вече със скоростта на Notepad, ами по скоро ще се доближи до тази на 3DSMax, което както и да го погледнем не е на добре. :) Затова излишните Plugin-и по-добре ги скрийте в една директория да речем HiddenPlugins, и когато ви потрябват си ги извадете от там.

До към септември 2012 си бях написал десетина плъгина за лични нужди, свързани с някои от архитектурните проекти, върху които работех и честно казано от тогава не ми остава време сядам да се занимавам с това (странно защо този времеви период съвпада със започването ми като студент в академията на Телерик :) ). И все пак въпреки, че имах желание да пипна малко въпросните плъгини, за да бъдат малко по-подходящи за гледане от други хора :) , реших да представя поне един от тях, който позволява движението в моделното пространство на Sketch Up да бъде като това в познатите ни компютърни игри като CounterStrike например. Поне според мен този plugin значително улеснява придвижването, особено в по-големи модели, където “зуумванете” и “орбитирането” (стандартните Tool-ове в Sketch Up за навигиране), просто не работят както трябва и навигирането става изключително затруднено.

Ето и линк към моя tool: DPY-Camera-24-09-2012.rar

За да го инсталирате, както казах и по-горе, просто слагате .rar-файла в директорията Plugins на SketchUp и го екстрактвате. В самия архив освен .rb файла има една папка, съдържаща картинки използвани от моят tool, както и Win32API.so файл, който е необходим, тъй като в скрипта съм използвал външни за Ruby функции, за да мога да манипулирам успешно мишката под Windows, тъй като за правилната работа на този tool е необходимо да мога да местя курсора на определена позиция.

Ще започна първо с обяснение за хората, които искат да използват моят tool, но не държат да знаят точно как работи кодът му. След като сте инсталирали плъгина, отваряте Sketch Up, а ако е отворен от преди го рестартирайте (тъй като плъгина се компилира и зарежда като функциониращ tool, при стартиране на програмата и няма да се зареди ако не рестартирате Sketch Up).  Намерете иконката в Toolbar-а, както е показано на картиката по-долу.

IncludeDPYCameraTool

DPY-Camera се стартира при цъкане на иконката в Toolbar-a. Изключването на tool-a, става посредством натискането на spacebar (което активира tool-a за селекция в Sketch Up), или при натискането на друг бутон, който активира съответен tool (например М за move). Най-долу в message bar-a се изписват помощни съобщения по време на използването на tool-a, указващи клавишите за навигация, стойност на скоростта и др. Скоростта се задава в m/s като ако искате да се движите по-бързо или по-бавно просто пишете цифрено новата стойност и натискате Enter. Това е удобно тъй като в зависимост от размерите на обекта, който искате да огледате, може да се налага да се приближавате детайлно близо(примерно при моделиране дизайна на една мебел), или пък да се придвижвате с много голяма скорост (ако моделирате един градски пейзаж да речем).

StartDPYCameraTool

След като сте стартирали и направили някакво движение ще забележите, че долу при съобщенията се появява един надпис “Click for MouseCorrection!”. Това е поради един бъг, който не успях да намеря по-умен начин да корегирам, свързан с малко отместване на данните за позицията на мишка от Win32API и от SketchUpRubyAPI. Просто цъкнете веднъж с мишката и ще можете да използвате пълната функционалност на tool-a от тук нататък. Ако не цъкнете – ами отново ще може да се придвижвате безпроблемно, но няма да можете да използвате бонус опцията наречена “Gun Mode” :) , при която в последствие ще можете да си включите един мерник и при цъкане да “гръмнете” (или в случая да изтриете от модела) обекта който ви е на мушката (edge, face, group, component или каквото ви се изпречи насреща :) ).

MouseCorrectionDPYCameraTool

След като веднъж сте кликнали с мишката ще видите, че долу в ляво надписа “MouseCorrection” е изчезнал и на негово място имате опция “GunMode On/Off”. GunMode се включва и изключва с Escape, както е и описано в message bar-a, и при включен GunMode мерникът става кръстче с точка по средата (ако е изключен стои само точката).

GunModeDPYCameraTool

Когато цъкнете при включен GunMode до курсора се изписва “BOOM!”  и се изтрива обекта, който е на мушката, така че бъдете внимателни при включен мерник :) (не че не можете с undo да си върнете изтритото, но все пак).

BoomDPYCameraTool

В общи линии това е по обяснението за използването на Tool-a. Надявам се да ви харесва и да ви бъде полезен. Имах желанието (но не и времето) за добавяне на повече функционалност – не само можеш да триеш при кликане с мишката ами примерно да рисуваш нещо върху модела или някаква друга функционално каквато може да се сети някой. Ако някой има идеи за подобрение нека пише или нека направо работи върху кода, който ще обясня накратко по-надолу.

Като начало каква е идеята на самия код, за да работи в конкретния случай. Движението със стрелките е просто и ясно – при задържане на някоя стрелките камерата започва да се движи с необходимата скорост в съответната посока. Как работи въртенето на камерата? Ами също не толкова сложно – при преместване на мишката tool-a отчита новата позиция на мишката, запазва мястото на камерата, премества фокусната точка върху някоя точка по лъча получен при свързването на позицията на камерата и новата точка на мишката. След като камерата е преместена нашият tool връща мястото на мишката в първоначалната позиция. Така мишката винаги стои по средата на екрана, във фокуса на камерата и съвпадайки с посоката на движение при задържана стрелка напред.

Поглеждайки в Sketch Up Ruby API можем да видим, че на пръв поглед един tool в скеч ъп има контрол над всичките ни необходими команди за прихващане на събития свързани с мишката и клавиатурата. На втори и трети поглед, почвайки да пишем кода, се сблъскваме с няколко проблема, които са свързани както с непълнотии в API-то, така и с бъгове в някои от съществуващите опции.

На първо време нека кажа какво трябва да се направи, за да си дефинираш един tool в Sketch Up. Ами всъщност е доста просто – просто си правиш един нов клас и него започваш да го пълниш с методите описани в документацията, необходими за да бъде разпозната в последствие от Sketch Up създадената инстанция на този клас като tool, а не като някакъв друг произволен клас. Важен в случая е метода activate, който активира tool-a при създаване на инстанцията на класа. В този метод се случват и началните действия, необходими за работата на нашия tool. Ето я и конкретната имплементация на този метод:

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
   def activate
     camera = Sketchup.active_model.active_view.camera
     newTarget = Geom::Point3d.linear_combination 1.0, camera.eye, 1.0, camera.zaxis.to_a
     camera.set camera.eye, newTarget, [0,0,1]
 
     @@mouseDouble = false  
     @@boom = false
     @@eraser = false
     @@mouseCorrected = false
     @@vk_up = false
	 @@vk_down = false
	 @@vk_left = false
	 @@vk_right = false
     @firstPress = true
	 @@animate = true
	 @c = Sketchup.active_model.active_view.center
     @corX = 0
     @corY = 0	 	 
	 @@v = 6/0.0254
	 @msg = "Use arrow keys and mouse to navigate! Velocity = " + (@@v*0.0254).to_s + " m/s. Change it by typing a desired velocity and pressing Enter."
	 Sketchup::set_status_text(@msg)
 
	 setCursorPos = Win32API.new("user32", "SetCursorPos", ['I', 'I'], 'V')
	 setCursorPos.Call(@c[0]+@corX,@c[1]+@corY)	 
   end

Тук е и момента да помоля за извинения читателя на тази статия за странното форматиране на кода. Истината е, че в Notepad++ индентирането си изглежда нормално, но пействайки го тук става някакво разминаване, което трябва да оправям ръчно. В момента, в който ми се отвори време, ще се опитам да го оправя, но в случай, че на някой му е неприятно да го гледа от тук, би могъл да отвори файла DPY_CAMERA_24_09_2012.rb, който е в горния архив.

В  методa activate си инициализирам началните стойности на глобалните и неглобалните променливи на класа. В самия му край (ред 96 и 97) може да видите и задаването на началното преместване на курсора в центъра на екрана. Тук е и първия проблем със Sketch Up Ruby API, с който трябваше да се сблъсквам – няма метод който да ми позволява преместването на мишката на определена позиция. След извесно търсене в нета, намерих решението на този проблем с външен метод от Win32API, който първо го дефинирам и после го извиквам. Това е един от най-малките проблеми, с които трябваше да се сблъскам, пишейки този плъгин. :)

Освен метода activate tool-a може да съдържа още един куп методи, които кръстени по определен начин, описан в Sketch Up Ruby API, биват разпознавани в последствие от Sketch Up и биват използвани за конкретни цели. Такива са методите OnMouseMove, OnKeyDown и други. Няма да ги описвам подробно. Който иска може да си прочете за тях в документацията, в която има и доста подходящи примери.
Накратко ще спомена и другите проблеми, с които се сблъсках. Метода, който използва Sketch Up за отчитане на координатите на текущата позиция на мишката се различава резултатите за координатите от външните методи, които ползвам от Win32API. Това наложи да използвам метод от Win32API и за взимането на координатите, за да няма разминавания. Това се случва в метода onMouseMove:

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
   def onMouseMove(flags, x, y, view)
 
     getCursorPos = Win32API.new("user32", "GetCursorPos", ['P'], 'V')
	 lpPoint = " " * 8 # store two LONGs
	 getCursorPos.Call(lpPoint)	 
	 p, q = lpPoint.unpack("LL") # get the actual values
     ray = view.pickray p-@corX, q-@corY
 
	 status = ray[1].samedirection? [0,0,1]
	 if(!status)       
	   view.camera.set ray[0], ray[1], [0,0,1]
	 end
 
	 setCursorPos = Win32API.new("user32", "SetCursorPos", ['I', 'I'], 'V')
	 setCursorPos.Call(@c[0]+@corX,@c[1]+@corY)
 
   end

Дотук добре. Истинският проблем обаче се появява, в момента, в който решавам, че искам да мога да включвам един мерник и с цъкане на мишката да “стрелям” и да изтривам обектите пред мерника. В Sketch Up Ruby API има готови класове и методи, с които мога да разбера кой е обекта под мишката ми и да го селектирам и съответно променя или направо изтрия. Това е чудесно, но с наличните разминавания на координатите на позициита на курсора, би било неприятно мерника ми да е нарисуван и да сочи към един обект, а аз като “стрелям” да изтрия някой съседен на него такъв. След като търсих начин да успея да унифицирам координатите от Sketch Up Ruby API и Win32API, за съжаление най-умното, което успях измисля е да поискам от потребителя на моя tool да направи просто един клик с мишката и отчитайки разликата от координатите на двете API-та, аз оттук нататък да използвам две променливи за корекция по x и корекция по y, като по този начин съм сигурен че мерника ми ще е напълно точен :) . Ако някой успее да измисли по-добро решение на този проблем, ще се радвам да го сподели.

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
   def onLButtonDown(flags, x, y, view)
       if(!@@mouseCorrected)
	     @@mouseCorrected = true
		 @corX = @c[0] - x
		 @corY = @c[1] - y
	   end   
       if(@@eraser and @@mouseCorrected)
	     @@boom = true
		 ph = view.pick_helper
		 ph.do_pick x,y
		 best = ph.best_picked
		 if(!best.deleted?) then best.erase! end
	   end
 
=begin	  ### Dictionaries and Attributes ###
	   if(!@@eraser and @@mouseCorrected)
		 ph = view.pick_helper
		 ph.do_pick x,y
		 best = ph.best_picked
		 inputpoint = view.inputpoint x, y
		 if(!best.deleted?)
		    best.set_attribute best.typename, "test", inputpoint.position
			best.attribute_dictionaries.each { |dict|
			    print=""
				dict.each { |key,value|
					print += dict.name.to_s + " --> " + key.to_s + " = " + value.to_s + "\n"
				}
				UI.messagebox(print)
			}			
		 end
	   end
=end	   
 
   end #end of LButtonDown

Големият закоментиран код в метода onLButtonDown (от ред 152 до ред 169), не е оставен там случайно. Тук съм си правил ескперименти с различни други функционалности, които биха могли да се добавят при кликане с мишката, освен сегашната функционалност за стреляне. Ако някои има идеи за реализация на рисуване с мишката или каквото и да било друго, може би тук е мястото, където трябва да добави малко код и да добави необходимата според него допълнителна функционалност на tool-а.

Последният проблем, с който се сблъсках, беше свързан с един бъг в Sketch Up Ruby API, свързан със събитието задържан клавиш. В документацията е записано, че при onKeyDown аз мога да имам информация за това дали клавиша е натиснат еднократно или е задържан. Това е вярно, но за съжаление работи само под Mac. Под Windows има някакъв бъг и тази опция просто не работи. Затова, вече решил проблема с ротацията на камерата, аз се сблъсках неочаквано и с проблем с нейното транслиране, тъй като искам при задържан бутон (стрелка) камерата да се транслира плавно с определена скорост в дадена посока. За да реализирам това успешно използвам комбинация от методите onKeyDown и onKeyUp, които ми дават информация кога някоя стрелка е натисната и кога е пусната. Тази информация съответно я пазя в една булева променлива за всяка от стрелките като тези променливи ги правя глобални за класа на моя tool. Всичко, което остава да направя, е да направя анимация на транслирането на камерата в зависимост от състоянието на тези булеви променливи. Анимация в Sketch Up се прави като се дефинира един допълнителен клас за анимацията.  Този клас трябва да има един метод на име nextFrame, чието име мисля че достатъчно ясно говори за какво служи :) . Ето и конкретната имплементация на класа за анимацията:

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class Animation
   def initialize
     @@DPY = DPYmoveCAMERAtool.new
     @camera = Sketchup.active_model.active_view.camera
	 @time = Sketchup.active_model.active_view.average_refresh_time * 10
	 @v = @@DPY.velocity
	 @msg = ""
	 @newEye = Geom::Point3d.new
	 @newTarget = Geom::Point3d.new
   end
 
   def nextFrame(view)
 
     @camera = view.camera
	 @time = view.average_refresh_time * 10
	 @v = @@DPY.velocity
 
	 if (@@DPY.vk_up)
	     @newEye = Geom::Point3d.linear_combination 1.0, @camera.eye, @v*@time, @camera.zaxis.to_a
         @newTarget = Geom::Point3d.linear_combination 1.0, @camera.target, @v*@time, @camera.zaxis.to_a	 
         view.camera.set @newEye, @newTarget, [0,0,1]
	 end
 
	 if (@@DPY.vk_down)
	     @newEye = Geom::Point3d.linear_combination 1.0, @camera.eye, -@v*@time, @camera.zaxis.to_a
         @newTarget = Geom::Point3d.linear_combination 1.0, @camera.target, -@v*@time, @camera.zaxis.to_a	 
         view.camera.set @newEye, @newTarget, [0,0,1] 
	 end
 
	 if (@@DPY.vk_left)
	     @newEye = Geom::Point3d.linear_combination 1.0, @camera.eye, -@v*@time, @camera.xaxis.to_a
         @newTarget = Geom::Point3d.linear_combination 1.0, @camera.target, -@v*@time, @camera.xaxis.to_a
         view.camera.set @newEye, @newTarget, [0,0,1]  
	 end
 
	 if (@@DPY.vk_right)
         @newEye = Geom::Point3d.linear_combination 1.0, @camera.eye, @v*@time, @camera.xaxis.to_a
         @newTarget = Geom::Point3d.linear_combination 1.0, @camera.target, @v*@time, @camera.xaxis.to_a	
         view.camera.set @newEye, @newTarget, [0,0,1] 
	 end
	 @msg = "Velocity = " + (@v*0.0254).to_s + " m/s. Position in space --> " + view.camera.eye[0].to_s + " " + view.camera.eye[1].to_s + " " + view.camera.eye[2].to_s
	 if(!@@DPY.mouseCorrected) then @msg = @msg + ". Click for MouseCorrection!" end
	 if(@@DPY.mouseCorrected)
	     @msg = @msg + ". Esc for GunMode On/Off: " 
		 if(@@DPY.eraser) then @msg = @msg + "On" end
		 if(!@@DPY.eraser) then @msg = @msg + "Off" end
	 end	 
	 if(!@@DPY.animate) 
	     @msg = ""
	 end
	 Sketchup::set_status_text(@msg)
	 view.show_frame
	 return @@DPY.animate
   end
 
end

Самата анимация се стартира при създаване на инстанция на класа Animation, което аз правя при първото извикване на метода onKeyDown от класа на моя tool:

197
198
199
200
201
202
203
204
205
206
207
208
209
   def onKeyDown(key, repeat, flags, view)   	 
 
     if(@firstPress)
	     @firstPress = false
		 Sketchup.active_model.active_view.animation =  Animation.new
	 end
 
	 if (key == VK_UP) then @@vk_up = true end	     
	 if (key == VK_DOWN) then @@vk_down = true end 
	 if (key == VK_RIGHT) then @@vk_right = true end
	 if (key == VK_LEFT) then @@vk_left = true end	 
 
   end

Кореспонденцията между двата класа я правя посредством глобалните променливи на класа на моя tool (това са тези променливи, започващи с двете кльомби :) ).
И така имайки вече цялата функционално – tool + animation, можем да заредим нашия tool в toolbar-a и при кликане да го стартираме:

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
######Creating new toolbar item
toolbar = UI::Toolbar.new "DPY_CAMERA"
 
######Adding new command to the toolbar item
DPY_CAMERA = UI::Command.new("DPY_CAMERA") { 
 
     Sketchup.active_model.start_operation 'DPY_CAMERA', true     
	 Sketchup.active_model.select_tool DPYmoveCAMERAtool.new
     Sketchup.active_model.commit_operation
 
 }
DPY_CAMERA.small_icon = File.join("DPY_CAMERA", "DPY_CAMERA_small.jpg")
DPY_CAMERA.large_icon = File.join("DPY_CAMERA", "DPY_CAMERA_large.jpg")
 
toolbar = toolbar.add_item DPY_CAMERA
toolbar.show

И това е всичко! Събирайки целия код в едно получаваме финалния резултат:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
require 'Win32API'
 
class Animation
   def initialize
     @@DPY = DPYmoveCAMERAtool.new
     @camera = Sketchup.active_model.active_view.camera
	 @time = Sketchup.active_model.active_view.average_refresh_time * 10
	 @v = @@DPY.velocity
	 @msg = ""
	 @newEye = Geom::Point3d.new
	 @newTarget = Geom::Point3d.new
   end
 
   def nextFrame(view)
 
     @camera = view.camera
	 @time = view.average_refresh_time * 10
	 @v = @@DPY.velocity
 
	 if (@@DPY.vk_up)
	     @newEye = Geom::Point3d.linear_combination 1.0, @camera.eye, @v*@time, @camera.zaxis.to_a
         @newTarget = Geom::Point3d.linear_combination 1.0, @camera.target, @v*@time, @camera.zaxis.to_a	 
         view.camera.set @newEye, @newTarget, [0,0,1]
	 end
 
	 if (@@DPY.vk_down)
	     @newEye = Geom::Point3d.linear_combination 1.0, @camera.eye, -@v*@time, @camera.zaxis.to_a
         @newTarget = Geom::Point3d.linear_combination 1.0, @camera.target, -@v*@time, @camera.zaxis.to_a	 
         view.camera.set @newEye, @newTarget, [0,0,1] 
	 end
 
	 if (@@DPY.vk_left)
	     @newEye = Geom::Point3d.linear_combination 1.0, @camera.eye, -@v*@time, @camera.xaxis.to_a
         @newTarget = Geom::Point3d.linear_combination 1.0, @camera.target, -@v*@time, @camera.xaxis.to_a
         view.camera.set @newEye, @newTarget, [0,0,1]  
	 end
 
	 if (@@DPY.vk_right)
         @newEye = Geom::Point3d.linear_combination 1.0, @camera.eye, @v*@time, @camera.xaxis.to_a
         @newTarget = Geom::Point3d.linear_combination 1.0, @camera.target, @v*@time, @camera.xaxis.to_a	
         view.camera.set @newEye, @newTarget, [0,0,1] 
	 end
	 @msg = "Velocity = " + (@v*0.0254).to_s + " m/s. Position in space --> " + view.camera.eye[0].to_s + " " + view.camera.eye[1].to_s + " " + view.camera.eye[2].to_s
	 if(!@@DPY.mouseCorrected) then @msg = @msg + ". Click for MouseCorrection!" end
	 if(@@DPY.mouseCorrected)
	     @msg = @msg + ". Esc for GunMode On/Off: " 
		 if(@@DPY.eraser) then @msg = @msg + "On" end
		 if(!@@DPY.eraser) then @msg = @msg + "Off" end
	 end	 
	 if(!@@DPY.animate) 
	     @msg = ""
	 end
	 Sketchup::set_status_text(@msg)
	 view.show_frame
	 return @@DPY.animate
   end
 
end
 
class DPYmoveCAMERAtool
 
   def initialize 
	 cursorPath2 = Sketchup.find_support_file ("DpyCameraCursor2.png", "Plugins/DPY_CAMERA/")
	 @@cursor2 = UI.create_cursor(cursorPath2, 5, 5)	
	 #cursorPath1 = Sketchup.find_support_file ("DpyCameraCursor1.png", "Plugins/DPY_CAMERA/")
	 #@@cursor1 = UI.create_cursor(cursorPath1, 5, 5)
   end
 
    def onSetCursor	
     UI.set_cursor(@@cursor2)
    end
 
   def activate
     camera = Sketchup.active_model.active_view.camera
	 newTarget = Geom::Point3d.linear_combination 1.0, camera.eye, 1.0, camera.zaxis.to_a
     camera.set camera.eye, newTarget, [0,0,1]
 
     @@mouseDouble = false  
	 @@boom = false
	 @@eraser = false
	 @@mouseCorrected = false
     @@vk_up = false
	 @@vk_down = false
	 @@vk_left = false
	 @@vk_right = false
     @firstPress = true
	 @@animate = true
	 @c = Sketchup.active_model.active_view.center
     @corX = 0
     @corY = 0	 	 
	 @@v = 6/0.0254
	 @msg = "Use arrow keys and mouse to navigate! Velocity = " + (@@v*0.0254).to_s + " m/s. Change it by typing a desired velocity and pressing Enter."
	 Sketchup::set_status_text(@msg)
 
	 setCursorPos = Win32API.new("user32", "SetCursorPos", ['I', 'I'], 'V')
	 setCursorPos.Call(@c[0]+@corX,@c[1]+@corY)	 
   end
 
   def draw(view)
     if(@@eraser and @@mouseCorrected)
		 view.drawing_color = "red"
		 d = 5
		 l = 25
		 view.draw2d GL_LINES, [@c[0],@c[1] - d,0],[@c[0],@c[1] - l,0] , [@c[0],@c[1] + d,0],[@c[0],@c[1] + l,0] , [@c[0] - d,@c[1],0],[@c[0] - l,@c[1],0] , [@c[0] + d,@c[1],0],[@c[0] + l,@c[1],0]
		 if(@@boom) then status = view.draw_text [@c[0] + d,@c[1] + d,0], "BOOM!" end
		 if(@@mouseDouble = true)
			 @@boom = false
			 @@mouseDouble = false
		 end
	 end
   end
 
   def deactivate(view)
     @@animate = false
   end
 
   def onCancel(reason, view)
     @@eraser = !@@eraser
   end
 
   def onUserText(text, view)
     if(text.to_f) then @@v = text.to_f/0.0254 end
   end
 
   def onLButtonDoubleClick(flags, x, y, view)
       if(@@eraser and @@mouseCorrected)
	     @@mouseDouble = true
	     @@boom = true
		 ph = view.pick_helper
		 ph.do_pick x,y
		 best = ph.best_picked
		 if(!best.deleted?) then best.erase! end
	   end	   
   end
 
   def onLButtonDown(flags, x, y, view)
       if(!@@mouseCorrected)
	     @@mouseCorrected = true
		 @corX = @c[0] - x
		 @corY = @c[1] - y
	   end   
       if(@@eraser and @@mouseCorrected)
	     @@boom = true
		 ph = view.pick_helper
		 ph.do_pick x,y
		 best = ph.best_picked
		 if(!best.deleted?) then best.erase! end
	   end
 
=begin	  ### Dictionaries and Attributes ###
	   if(!@@eraser and @@mouseCorrected)
		 ph = view.pick_helper
		 ph.do_pick x,y
		 best = ph.best_picked
		 inputpoint = view.inputpoint x, y
		 if(!best.deleted?)
		    best.set_attribute best.typename, "test", inputpoint.position
			best.attribute_dictionaries.each { |dict|
			    print=""
				dict.each { |key,value|
					print += dict.name.to_s + " --> " + key.to_s + " = " + value.to_s + "\n"
				}
				UI.messagebox(print)
			}			
		 end
	   end
=end	   
 
   end #end of LButtonDown
 
   def onLButtonUp(flags, x, y, view)
     @@boom = false
   end
 
   def onMouseMove(flags, x, y, view)
 
     getCursorPos = Win32API.new("user32", "GetCursorPos", ['P'], 'V')
	 lpPoint = " " * 8 # store two LONGs
	 getCursorPos.Call(lpPoint)	 
	 p, q = lpPoint.unpack("LL") # get the actual values
     ray = view.pickray p-@corX, q-@corY
 
	 status = ray[1].samedirection? [0,0,1]
	 if(!status)       
	   view.camera.set ray[0], ray[1], [0,0,1]
	 end
 
	 setCursorPos = Win32API.new("user32", "SetCursorPos", ['I', 'I'], 'V')
	 setCursorPos.Call(@c[0]+@corX,@c[1]+@corY)
 
   end
 
   def onKeyDown(key, repeat, flags, view)   	 
 
     if(@firstPress)
	     @firstPress = false
		 Sketchup.active_model.active_view.animation =  Animation.new
	 end
 
	 if (key == VK_UP) then @@vk_up = true end	     
	 if (key == VK_DOWN) then @@vk_down = true end 
	 if (key == VK_RIGHT) then @@vk_right = true end
	 if (key == VK_LEFT) then @@vk_left = true end	 
 
   end
 
   def onKeyUp(key, repeat, flags, view)
     if (key == VK_UP) then @@vk_up = false end 
	 if (key == VK_DOWN) then @@vk_down = false end 
	 if (key == VK_LEFT) then @@vk_left = false end 
	 if (key == VK_RIGHT) then @@vk_right = false end 
   end
 
   def animate
     @@animate
   end
 
   def vk_up
     @@vk_up
   end
 
   def vk_down
     @@vk_down
   end
 
   def vk_left
     @@vk_left
   end
 
   def vk_right
     @@vk_right
   end
 
   def velocity
     @@v
   end
 
   def mouseCorrected
     @@mouseCorrected
   end
 
   def eraser
     @@eraser
   end  
 
end # end class DPYmoveCAMERAtool definition
 
######Dobawqne na toolbar
toolbar = UI::Toolbar.new "DPY_CAMERA"
 
######Dobawqne na komanda tetrahedron kam toolbara
DPY_CAMERA = UI::Command.new("DPY_CAMERA") { 
 
     Sketchup.active_model.start_operation 'DPY_CAMERA', true     
	 Sketchup.active_model.select_tool DPYmoveCAMERAtool.new
     Sketchup.active_model.commit_operation
 
 }
DPY_CAMERA.small_icon = File.join("DPY_CAMERA", "DPY_CAMERA_small.jpg")
DPY_CAMERA.large_icon = File.join("DPY_CAMERA", "DPY_CAMERA_large.jpg")
 
toolbar = toolbar.add_item DPY_CAMERA
toolbar.show

You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>