1
by Henk Krus
Initial Launchpad setup |
1 |
! This program plots a function of two variables. The function, called
|
2 |
! func_to_plot, is an external procedure at the end of the file.
|
|
3 |
! This begins with the same module used in the modview example, followed by
|
|
4 |
! another module for plotting the function, called function_plotter.
|
|
5 |
! You might want to change default initial settings in modules modview and
|
|
6 |
! function_plotter.
|
|
7 |
||
8 |
! William F. Mitchell
|
|
9 |
! william.mitchell@nist.gov
|
|
10 |
! Mathematical and Computational Sciences Division
|
|
11 |
! National Institute of Standards and Technology
|
|
12 |
! August, 1999
|
|
13 |
||
14 |
!---------------------------------------------------------------------------
|
|
15 |
||
16 |
module view_modifier |
|
17 |
||
18 |
! This module provides facilities to modify the view in an OpenGL window.
|
|
19 |
! The mouse buttons and keyboard arrow keys can be used to zoom, pan,
|
|
20 |
! rotate and change the scale. A menu or submenu can be used to select which
|
|
21 |
! buttons perform which function and to reset the view to the initial settings.
|
|
22 |
! This is limited to one window.
|
|
23 |
||
24 |
! William F. Mitchell
|
|
25 |
! william.mitchell@nist.gov
|
|
26 |
! Mathematical and Computational Sciences Division
|
|
27 |
! National Institute of Standards and Technology
|
|
28 |
! April, 1998
|
|
29 |
||
30 |
! To use this module:
|
|
31 |
!
|
|
32 |
! 1) put a USE view_modifier statement in any program unit that calls a
|
|
33 |
! procedure in this module
|
|
34 |
!
|
|
35 |
! 2) set the initial operation assignments, view and scale below the
|
|
36 |
! "Initial configuration" comment below
|
|
37 |
!
|
|
38 |
! 3) call view_modifier_init after glutCreateWindow
|
|
39 |
! This is a function that returns integer(kind=glcint) menuid. The menuid
|
|
40 |
! is the ID returned by glutCreateMenu. You can either use the view_modifier
|
|
41 |
! menu as your menu by calling glutAttachMenu immediately after
|
|
42 |
! view_modifier_init, as in
|
|
43 |
! menuid = view_modifier_init()
|
|
44 |
! call glutAttachMenu(GLUT_RIGHT_BUTTON)
|
|
45 |
! or by using the menuid to attach a submenu to your own menu, as in
|
|
46 |
! call glutAddSubMenu("View Modifier",menuid)
|
|
47 |
!
|
|
48 |
! 4) in any callback functions that update the display, put
|
|
49 |
! call reset_view
|
|
50 |
! as the first executable statement
|
|
51 |
!
|
|
52 |
! Note that view_modifier_init sets the callback functions for glutMouseFunc,
|
|
53 |
! glutMotionFunc and glutSpecialFunc, so don't call these yourself
|
|
54 |
!
|
|
55 |
! The menu allows you to select what operation is attached to the left and
|
|
56 |
! middle mouse buttons and arrow keys, reset to the initial view, and quit.
|
|
57 |
! The right mouse button should be used for the menu.
|
|
58 |
||
59 |
use opengl_gl |
|
60 |
use opengl_glu |
|
61 |
use opengl_glut |
|
62 |
implicit none
|
|
63 |
private
|
|
64 |
public :: view_modifier_init, reset_view |
|
65 |
private :: ZOOM, PAN, ROTATE, SCALEX, SCALEY, SCALEZ, RESET, ABOVE, QUIT, & |
|
66 |
PI, & |
|
67 |
left_button_func, middle_button_func, arrow_key_func, & |
|
68 |
init_lookat, init_lookfrom, & |
|
69 |
init_xscale_factor, init_yscale_factor, init_zscale_factor, & |
|
70 |
angle, shift, xscale_factor, yscale_factor, zscale_factor, & |
|
71 |
moving_left, moving_middle, begin_left, begin_middle, & |
|
72 |
cart2sphere, sphere2cart, cart3D_plus_cart3D, cart3D_minus_cart3D, & |
|
73 |
reset_to_init, mouse, motion, arrows, & |
|
74 |
menu_handler, set_left_button, set_middle_button, set_arrow_keys |
|
75 |
||
76 |
integer(kind=glcint), parameter :: ZOOM = 1, PAN = 2, ROTATE = 3, SCALEX = 4, & |
|
77 |
SCALEY = 5, SCALEZ = 6 |
|
78 |
integer(kind=glcint), parameter :: RESET = 10, ABOVE = 11, QUIT = 12 |
|
79 |
real(kind=gldouble), parameter :: PI = 3.141592653589793_gldouble |
|
80 |
||
81 |
type, private :: cart2D ! 2D cartesian coordinates |
|
82 |
real(kind=gldouble) :: x, y |
|
83 |
end type cart2D |
|
84 |
||
85 |
type, private :: cart3D ! 3D cartesian coordinates |
|
86 |
real(kind=gldouble) :: x, y, z |
|
87 |
end type cart3D |
|
88 |
||
89 |
type, private :: sphere3D ! 3D spherical coordinates |
|
90 |
real(kind=gldouble) :: theta, phi, rho |
|
91 |
end type sphere3D |
|
92 |
||
93 |
type(cart2D), save :: angle |
|
94 |
type(cart3D), save :: shift |
|
95 |
real(kind=gldouble), save :: xscale_factor, yscale_factor, zscale_factor |
|
96 |
logical, save :: moving_left, moving_middle |
|
97 |
type(cart2D), save :: begin_left, begin_middle |
|
98 |
||
99 |
interface operator(+) |
|
100 |
module procedure cart3D_plus_cart3D |
|
101 |
end interface
|
|
102 |
interface operator(-) |
|
103 |
module procedure cart3D_minus_cart3D |
|
104 |
end interface
|
|
105 |
||
106 |
! ------- Initial configuration -------
|
|
107 |
||
108 |
! Set the initial operation performed by each button and the arrow keys.
|
|
109 |
! The operations are ZOOM, PAN, ROTATE, SCALEX, SCALEY, and SCALEZ
|
|
110 |
||
111 |
integer, save :: left_button_func = ROTATE, & |
|
112 |
middle_button_func = ZOOM, & |
|
113 |
arrow_key_func = PAN |
|
114 |
||
115 |
! Set the initial view as the point you are looking at, the point you are
|
|
116 |
! looking from, and the scale factors
|
|
117 |
||
118 |
type(cart3D), parameter :: & |
|
119 |
init_lookat = cart3D(0.5_gldouble, 0.5_gldouble, 0.0_gldouble), & |
|
120 |
init_lookfrom = cart3D(5.0_gldouble, 10.0_gldouble, 2.5_gldouble) |
|
121 |
||
122 |
real(kind=gldouble), parameter :: & |
|
123 |
init_xscale_factor = 1.0_gldouble, & |
|
124 |
init_yscale_factor = 1.0_gldouble, & |
|
125 |
init_zscale_factor = 1.0_gldouble |
|
126 |
||
127 |
! -------- end of Initial configuration ------
|
|
128 |
||
129 |
contains
|
|
130 |
||
131 |
! -------------
|
|
132 |
subroutine reset_to_init |
|
133 |
! -------------
|
|
134 |
||
135 |
! This resets the view to the initial configuration
|
|
136 |
||
137 |
type(sphere3D) :: slookfrom |
|
138 |
||
139 |
slookfrom = cart2sphere(init_lookfrom-init_lookat) |
|
140 |
angle%x = -180.0_gldouble*slookfrom%theta/PI - 90.0_gldouble |
|
141 |
angle%y = -180.0_gldouble*slookfrom%phi/PI |
|
142 |
shift%x = 0.0_gldouble |
|
143 |
shift%y = 0.0_gldouble |
|
144 |
shift%z = -slookfrom%rho |
|
145 |
xscale_factor = init_xscale_factor |
|
146 |
yscale_factor = init_yscale_factor |
|
147 |
zscale_factor = init_zscale_factor |
|
148 |
||
149 |
call glutPostRedisplay |
|
150 |
||
151 |
return
|
|
152 |
end subroutine reset_to_init |
|
153 |
||
154 |
! ---------------
|
|
155 |
subroutine view_from_above |
|
156 |
! ---------------
|
|
157 |
||
158 |
! This sets the view to be from straight above
|
|
159 |
||
160 |
type(sphere3D) :: slookfrom |
|
161 |
||
162 |
slookfrom = cart2sphere(cart3D(0.0,0.0,1.0)) |
|
163 |
angle%x = -180.0_gldouble*slookfrom%theta/PI |
|
164 |
angle%y = -180.0_gldouble*slookfrom%phi/PI |
|
165 |
||
166 |
call glutPostRedisplay |
|
167 |
||
168 |
return
|
|
169 |
end subroutine view_from_above |
|
170 |
||
171 |
! ----------
|
|
172 |
subroutine reset_view |
|
173 |
! ----------
|
|
174 |
||
175 |
! This routine resets the view to the current orientation and scale
|
|
176 |
||
177 |
call glMatrixMode(GL_MODELVIEW) |
|
178 |
call glPopMatrix |
|
179 |
call glPushMatrix |
|
180 |
call glTranslated(shift%x, shift%y, shift%z) |
|
181 |
call glRotated(angle%x, 0.0_gldouble, 0.0_gldouble, 1.0_gldouble) |
|
182 |
call glRotated(angle%y, cos(PI*angle%x/180.0_gldouble), & |
|
183 |
-sin(PI*angle%x/180.0_gldouble), 0.0_gldouble) |
|
184 |
call glTranslated(-init_lookat%x, -init_lookat%y, -init_lookat%z) |
|
185 |
call glScaled(xscale_factor,yscale_factor,zscale_factor) |
|
186 |
||
187 |
return
|
|
188 |
end subroutine reset_view |
|
189 |
||
190 |
! -----
|
|
191 |
subroutine mouse(button, state, x, y) bind(c,name="") |
|
192 |
! -----
|
|
193 |
integer(kind=glcint), value :: button, state, x, y |
|
194 |
||
195 |
! This gets called when a mouse button changes
|
|
196 |
||
197 |
if (button == GLUT_LEFT_BUTTON .and. state == GLUT_DOWN) then |
|
198 |
moving_left = .true. |
|
199 |
begin_left = cart2D(x,y) |
|
200 |
endif
|
|
201 |
if (button == GLUT_LEFT_BUTTON .and. state == GLUT_UP) then |
|
202 |
moving_left = .false. |
|
203 |
endif
|
|
204 |
if (button == GLUT_MIDDLE_BUTTON .and. state == GLUT_DOWN) then |
|
205 |
moving_middle = .true. |
|
206 |
begin_middle = cart2D(x,y) |
|
207 |
endif
|
|
208 |
if (button == GLUT_MIDDLE_BUTTON .and. state == GLUT_UP) then |
|
209 |
moving_middle = .false. |
|
210 |
endif
|
|
211 |
end subroutine mouse |
|
212 |
||
213 |
! ------
|
|
214 |
subroutine motion(x, y) bind(c,name="") |
|
215 |
! ------
|
|
216 |
integer(kind=glcint), value :: x, y |
|
217 |
||
218 |
! This gets called when the mouse moves
|
|
219 |
||
220 |
integer :: button_function |
|
221 |
type(cart2D) :: begin |
|
222 |
real(kind=gldouble) :: factor |
|
223 |
||
224 |
! Determine and apply the button function
|
|
225 |
||
226 |
if (moving_left) then |
|
227 |
button_function = left_button_func |
|
228 |
begin = begin_left |
|
229 |
else if(moving_middle) then |
|
230 |
button_function = middle_button_func |
|
231 |
begin = begin_middle |
|
232 |
end if
|
|
233 |
||
234 |
select case(button_function) |
|
235 |
case (ZOOM) |
|
236 |
if (y < begin%y) then |
|
237 |
factor = 1.0_gldouble/(1.0_gldouble + .002_gldouble*(begin%y-y)) |
|
238 |
else if (y > begin%y) then |
|
239 |
factor = 1.0_gldouble + .002_gldouble*(y-begin%y) |
|
240 |
else
|
|
241 |
factor = 1.0_gldouble |
|
242 |
end if
|
|
243 |
shift%z = factor*shift%z |
|
244 |
case (PAN) |
|
245 |
shift%x = shift%x + .01*(x - begin%x) |
|
246 |
shift%y = shift%y - .01*(y - begin%y) |
|
247 |
case (ROTATE) |
|
248 |
angle%x = angle%x + (x - begin%x) |
|
249 |
angle%y = angle%y + (y - begin%y) |
|
250 |
case (SCALEX) |
|
251 |
if (y < begin%y) then |
|
252 |
factor = 1.0_gldouble + .002_gldouble*(begin%y-y) |
|
253 |
else if (y > begin%y) then |
|
254 |
factor = 1.0_gldouble/(1.0_gldouble + .002_gldouble*(y-begin%y)) |
|
255 |
else
|
|
256 |
factor = 1.0_gldouble |
|
257 |
end if
|
|
258 |
xscale_factor = xscale_factor * factor |
|
259 |
case (SCALEY) |
|
260 |
if (y < begin%y) then |
|
261 |
factor = 1.0_gldouble + .002_gldouble*(begin%y-y) |
|
262 |
else if (y > begin%y) then |
|
263 |
factor = 1.0_gldouble/(1.0_gldouble + .002_gldouble*(y-begin%y)) |
|
264 |
else
|
|
265 |
factor = 1.0_gldouble |
|
266 |
end if
|
|
267 |
yscale_factor = yscale_factor * factor |
|
268 |
case (SCALEZ) |
|
269 |
if (y < begin%y) then |
|
270 |
factor = 1.0_gldouble + .002_gldouble*(begin%y-y) |
|
271 |
else if (y > begin%y) then |
|
272 |
factor = 1.0_gldouble/(1.0_gldouble + .002_gldouble*(y-begin%y)) |
|
273 |
else
|
|
274 |
factor = 1.0_gldouble |
|
275 |
end if
|
|
276 |
zscale_factor = zscale_factor * factor |
|
277 |
end select
|
|
278 |
||
279 |
! update private variables and redisplay
|
|
280 |
||
281 |
if (moving_left) then |
|
282 |
begin_left = cart2D(x,y) |
|
283 |
else if(moving_middle) then |
|
284 |
begin_middle = cart2D(x,y) |
|
285 |
endif
|
|
286 |
||
287 |
if (moving_left .or. moving_middle) then |
|
288 |
call glutPostRedisplay |
|
289 |
endif
|
|
290 |
||
291 |
return
|
|
292 |
end subroutine motion |
|
293 |
||
294 |
! ------
|
|
295 |
subroutine arrows(key, x, y) bind(c,name="") |
|
296 |
! ------
|
|
297 |
integer(glcint), value :: key, x, y |
|
298 |
||
299 |
! This routine handles the arrow key operations
|
|
300 |
||
301 |
real(kind=gldouble) :: factor |
|
302 |
||
303 |
select case(arrow_key_func) |
|
304 |
case(ZOOM) |
|
305 |
select case(key) |
|
306 |
case(GLUT_KEY_DOWN) |
|
307 |
factor = 1.0_gldouble + .02_gldouble |
|
308 |
case(GLUT_KEY_UP) |
|
309 |
factor = 1.0_gldouble/(1.0_gldouble + .02_gldouble) |
|
310 |
case default |
|
311 |
factor = 1.0_gldouble |
|
312 |
end select
|
|
313 |
shift%z = factor*shift%z |
|
314 |
case(PAN) |
|
315 |
select case(key) |
|
316 |
case(GLUT_KEY_LEFT) |
|
317 |
shift%x = shift%x - .02 |
|
318 |
case(GLUT_KEY_RIGHT) |
|
319 |
shift%x = shift%x + .02 |
|
320 |
case(GLUT_KEY_DOWN) |
|
321 |
shift%y = shift%y - .02 |
|
322 |
case(GLUT_KEY_UP) |
|
323 |
shift%y = shift%y + .02 |
|
324 |
end select
|
|
325 |
case(ROTATE) |
|
326 |
select case(key) |
|
327 |
case(GLUT_KEY_LEFT) |
|
328 |
angle%x = angle%x - 1.0_gldouble |
|
329 |
case(GLUT_KEY_RIGHT) |
|
330 |
angle%x = angle%x + 1.0_gldouble |
|
331 |
case(GLUT_KEY_DOWN) |
|
332 |
angle%y = angle%y + 1.0_gldouble |
|
333 |
case(GLUT_KEY_UP) |
|
334 |
angle%y = angle%y - 1.0_gldouble |
|
335 |
end select
|
|
336 |
case(SCALEX) |
|
337 |
select case(key) |
|
338 |
case(GLUT_KEY_DOWN) |
|
339 |
factor = 1.0_gldouble/(1.0_gldouble + .02_gldouble) |
|
340 |
case(GLUT_KEY_UP) |
|
341 |
factor = 1.0_gldouble + .02_gldouble |
|
342 |
case default |
|
343 |
factor = 1.0_gldouble |
|
344 |
end select
|
|
345 |
xscale_factor = xscale_factor * factor |
|
346 |
case(SCALEY) |
|
347 |
select case(key) |
|
348 |
case(GLUT_KEY_DOWN) |
|
349 |
factor = 1.0_gldouble/(1.0_gldouble + .02_gldouble) |
|
350 |
case(GLUT_KEY_UP) |
|
351 |
factor = 1.0_gldouble + .02_gldouble |
|
352 |
case default |
|
353 |
factor = 1.0_gldouble |
|
354 |
end select
|
|
355 |
yscale_factor = yscale_factor * factor |
|
356 |
case(SCALEZ) |
|
357 |
select case(key) |
|
358 |
case(GLUT_KEY_DOWN) |
|
359 |
factor = 1.0_gldouble/(1.0_gldouble + .02_gldouble) |
|
360 |
case(GLUT_KEY_UP) |
|
361 |
factor = 1.0_gldouble + .02_gldouble |
|
362 |
case default |
|
363 |
factor = 1.0_gldouble |
|
364 |
end select
|
|
365 |
zscale_factor = zscale_factor * factor |
|
366 |
||
367 |
end select
|
|
368 |
|
|
369 |
call glutPostRedisplay |
|
370 |
||
371 |
return
|
|
372 |
end subroutine arrows |
|
373 |
||
374 |
! ------------
|
|
375 |
subroutine menu_handler(value) bind(c,name="") |
|
376 |
! ------------
|
|
377 |
integer(kind=glcint), value :: value |
|
378 |
||
379 |
! This routine handles the first level entries in the menu
|
|
380 |
||
381 |
select case(value) |
|
382 |
||
383 |
case(RESET) |
|
384 |
call reset_to_init |
|
385 |
case(ABOVE) |
|
386 |
call view_from_above |
|
387 |
case(QUIT) |
|
388 |
stop
|
|
389 |
||
390 |
end select
|
|
391 |
||
392 |
return
|
|
393 |
end subroutine menu_handler |
|
394 |
||
395 |
! ---------------
|
|
396 |
subroutine set_left_button(value) bind(c,name="") |
|
397 |
! ---------------
|
|
398 |
integer(kind=glcint), value :: value |
|
399 |
||
400 |
! This routine sets the function of the left button as given by menu selection
|
|
401 |
||
402 |
left_button_func = value |
|
403 |
||
404 |
return
|
|
405 |
end subroutine set_left_button |
|
406 |
||
407 |
! -----------------
|
|
408 |
subroutine set_middle_button(value) bind(c,name="") |
|
409 |
! -----------------
|
|
410 |
integer(kind=glcint), value :: value |
|
411 |
||
412 |
! This routine sets the function of the middle button as given by menu selection
|
|
413 |
||
414 |
middle_button_func = value |
|
415 |
||
416 |
return
|
|
417 |
end subroutine set_middle_button |
|
418 |
||
419 |
! --------------
|
|
420 |
subroutine set_arrow_keys(value) bind(c,name="") |
|
421 |
! --------------
|
|
422 |
integer(kind=glcint), value :: value |
|
423 |
||
424 |
! This routine sets the function of the arrow keys as given by menu selection
|
|
425 |
||
426 |
arrow_key_func = value |
|
427 |
||
428 |
return
|
|
429 |
end subroutine set_arrow_keys |
|
430 |
||
431 |
! ------------------
|
|
432 |
function view_modifier_init() result(menuid) |
|
433 |
! ------------------
|
|
434 |
integer(kind=glcint) :: menuid |
|
435 |
||
436 |
! This initializes the view modifier variables and sets initial view.
|
|
437 |
! It should be called immediately after glutCreateWindow
|
|
438 |
||
439 |
integer(kind=glcint) :: button_left, button_middle, arrow_keys |
|
440 |
||
441 |
! set the callback functions
|
|
442 |
||
443 |
call glutMouseFunc(mouse) |
|
444 |
call glutMotionFunc(motion) |
|
445 |
call glutSpecialFunc(arrows) |
|
446 |
||
447 |
! create the menu
|
|
448 |
||
449 |
button_left = glutCreateMenu(set_left_button) |
|
450 |
call glutAddMenuEntry("rotate"//char(0),ROTATE) |
|
451 |
call glutAddMenuEntry("zoom"//char(0),ZOOM) |
|
452 |
call glutAddMenuEntry("pan"//char(0),PAN) |
|
453 |
call glutAddMenuEntry("scale x"//char(0),SCALEX) |
|
454 |
call glutAddMenuEntry("scale y"//char(0),SCALEY) |
|
455 |
call glutAddMenuEntry("scale z"//char(0), SCALEZ) |
|
456 |
button_middle = glutCreateMenu(set_middle_button) |
|
457 |
call glutAddMenuEntry("rotate"//char(0),ROTATE) |
|
458 |
call glutAddMenuEntry("zoom"//char(0),ZOOM) |
|
459 |
call glutAddMenuEntry("pan"//char(0),PAN) |
|
460 |
call glutAddMenuEntry("scale x"//char(0),SCALEX) |
|
461 |
call glutAddMenuEntry("scale y"//char(0),SCALEY) |
|
462 |
call glutAddMenuEntry("scale z"//char(0), SCALEZ) |
|
463 |
arrow_keys = glutCreateMenu(set_arrow_keys) |
|
464 |
call glutAddMenuEntry("rotate"//char(0),ROTATE) |
|
465 |
call glutAddMenuEntry("zoom"//char(0),ZOOM) |
|
466 |
call glutAddMenuEntry("pan"//char(0),PAN) |
|
467 |
call glutAddMenuEntry("scale x"//char(0),SCALEX) |
|
468 |
call glutAddMenuEntry("scale y"//char(0),SCALEY) |
|
469 |
call glutAddMenuEntry("scale z"//char(0), SCALEZ) |
|
470 |
menuid = glutCreateMenu(menu_handler) |
|
471 |
call glutAddSubMenu("left mouse button"//char(0),button_left) |
|
472 |
call glutAddSubMenu("middle mouse button"//char(0),button_middle) |
|
473 |
call glutAddSubMenu("arrow keys"//char(0),arrow_keys) |
|
474 |
call glutAddMenuEntry("reset to initial view"//char(0),RESET) |
|
475 |
call glutAddMenuEntry("view from above"//char(0),ABOVE) |
|
476 |
call glutAddMenuEntry("quit"//char(0),QUIT) |
|
477 |
||
478 |
! set the perspective
|
|
479 |
||
480 |
call glMatrixMode(GL_PROJECTION) |
|
481 |
call gluPerspective(10.0_gldouble, 1.0_gldouble, 0.1_gldouble, 200.0_gldouble) |
|
482 |
||
483 |
! set the initial view
|
|
484 |
||
485 |
call glMatrixMode(GL_MODELVIEW) |
|
486 |
call glPushMatrix |
|
487 |
call reset_to_init |
|
488 |
||
489 |
return
|
|
490 |
end function view_modifier_init |
|
491 |
||
492 |
! -----------
|
|
493 |
function sphere2cart(spoint) result(cpoint) |
|
494 |
! -----------
|
|
495 |
type(sphere3D), intent(in) :: spoint |
|
496 |
type(cart3D) :: cpoint |
|
497 |
||
498 |
! This converts a 3D point from spherical to cartesean coordinates
|
|
499 |
||
500 |
real(kind=gldouble) :: t,p,r |
|
501 |
||
502 |
t=spoint%theta |
|
503 |
p=spoint%phi |
|
504 |
r=spoint%rho |
|
505 |
||
506 |
cpoint%x = r*cos(t)*sin(p) |
|
507 |
cpoint%y = r*sin(t)*sin(p) |
|
508 |
cpoint%z = r*cos(p) |
|
509 |
||
510 |
return
|
|
511 |
end function sphere2cart |
|
512 |
||
513 |
! -----------
|
|
514 |
function cart2sphere(cpoint) result(spoint) |
|
515 |
! -----------
|
|
516 |
type(cart3D), intent(in) :: cpoint |
|
517 |
type(sphere3D) :: spoint |
|
518 |
||
519 |
! This converts a 3D point from cartesean to spherical coordinates
|
|
520 |
||
521 |
real(kind=gldouble) :: x,y,z |
|
522 |
||
523 |
x=cpoint%x |
|
524 |
y=cpoint%y |
|
525 |
z=cpoint%z |
|
526 |
||
527 |
spoint%rho = sqrt(x*x+y*y+z*z) |
|
528 |
if (x==0.0_gldouble .and. y==0.0_gldouble) then |
|
529 |
spoint%theta = 0.0_gldouble |
|
530 |
else
|
|
531 |
spoint%theta = atan2(y,x) |
|
532 |
end if
|
|
533 |
if (spoint%rho == 0.0_gldouble) then |
|
534 |
spoint%phi = 0.0_gldouble |
|
535 |
else
|
|
536 |
spoint%phi = acos(z/spoint%rho) |
|
537 |
endif
|
|
538 |
||
539 |
return
|
|
540 |
end function cart2sphere |
|
541 |
||
542 |
! ------------------
|
|
543 |
function cart3D_plus_cart3D(cart1,cart2) result(cart3) |
|
544 |
! ------------------
|
|
545 |
type(cart3D), intent(in) :: cart1, cart2 |
|
546 |
type(cart3D) :: cart3 |
|
547 |
||
548 |
! Compute the sum of two 3D cartesean points
|
|
549 |
||
550 |
cart3%x = cart1%x + cart2%x |
|
551 |
cart3%y = cart1%y + cart2%y |
|
552 |
cart3%z = cart1%z + cart2%z |
|
553 |
||
554 |
return
|
|
555 |
end function cart3D_plus_cart3D |
|
556 |
||
557 |
! -------------------
|
|
558 |
function cart3D_minus_cart3D(cart1,cart2) result(cart3) |
|
559 |
! -------------------
|
|
560 |
type(cart3D), intent(in) :: cart1, cart2 |
|
561 |
type(cart3D) :: cart3 |
|
562 |
||
563 |
! Compute the difference of two 3D cartesean points
|
|
564 |
||
565 |
cart3%x = cart1%x - cart2%x |
|
566 |
cart3%y = cart1%y - cart2%y |
|
567 |
cart3%z = cart1%z - cart2%z |
|
568 |
||
569 |
return
|
|
570 |
end function cart3D_minus_cart3D |
|
571 |
||
572 |
end module view_modifier |
|
573 |
||
574 |
!---------------------------------------------------------------------------
|
|
575 |
||
576 |
module function_plotter |
|
577 |
use opengl_gl |
|
578 |
use opengl_glut |
|
579 |
use view_modifier |
|
580 |
implicit none
|
|
581 |
private
|
|
582 |
public :: display, draw_func, menu_handler2, make_menu |
|
583 |
||
584 |
! symbolic constants
|
|
585 |
||
586 |
integer, parameter :: surfgrid_toggle = 1, & |
|
587 |
surfsolid_toggle = 2, & |
|
588 |
contour_toggle = 3, & |
|
589 |
quit_selected = 4 |
|
590 |
||
591 |
integer, parameter :: set_nx = 1, & |
|
592 |
set_ny = 2, & |
|
593 |
set_ncontour = 3, & |
|
594 |
set_contour_val = 4, & |
|
595 |
set_xrange = 5, & |
|
596 |
set_yrange = 6, & |
|
597 |
reset_params = 7 |
|
598 |
||
599 |
integer, parameter :: black_contour = 1, & |
|
600 |
rainbow_contour = 2 |
|
601 |
||
602 |
integer, parameter :: white_surface = 1, & |
|
603 |
red_surface = 2, & |
|
604 |
rainbow_surface = 3 |
|
605 |
||
606 |
! Default initial settings
|
|
607 |
||
608 |
integer, parameter :: init_ngridx = 40, & |
|
609 |
init_ngridy = 40, & |
|
610 |
init_num_contour = 20, & |
|
611 |
init_contour_color = black_contour, & |
|
612 |
init_surface_color = rainbow_surface |
|
613 |
||
614 |
real(GLDOUBLE), parameter :: init_minx = 0.0_GLDOUBLE, & |
|
615 |
init_maxx = 1.0_GLDOUBLE, & |
|
616 |
init_miny = 0.0_GLDOUBLE, & |
|
617 |
init_maxy = 1.0_GLDOUBLE |
|
618 |
||
619 |
logical, parameter :: init_draw_surface_grid = .false., & |
|
620 |
init_draw_surface_solid = .true., & |
|
621 |
init_draw_contour = .true. |
|
622 |
||
623 |
! Current settings
|
|
624 |
||
625 |
integer :: ngridx = init_ngridx, & |
|
626 |
ngridy = init_ngridy, & |
|
627 |
num_contour = init_num_contour, & |
|
628 |
contour_color = init_contour_color, & |
|
629 |
surface_color = init_surface_color |
|
630 |
||
631 |
real(GLDOUBLE) :: minx = init_minx, & |
|
632 |
maxx = init_maxx, & |
|
633 |
miny = init_miny, & |
|
634 |
maxy = init_maxy, & |
|
635 |
minz = 0.0_GLDOUBLE, & |
|
636 |
maxz = 0.0_GLDOUBLE |
|
637 |
||
638 |
logical :: draw_surface_grid = init_draw_surface_grid, & |
|
639 |
draw_surface_solid = init_draw_surface_solid, & |
|
640 |
draw_contour = init_draw_contour, & |
|
641 |
contour_values_given = .false. |
|
642 |
||
643 |
real(GLDOUBLE), allocatable :: actual_contours(:) |
|
644 |
||
645 |
contains
|
|
646 |
||
647 |
subroutine display() bind(c) |
|
648 |
||
649 |
! This gets called when the display needs to be redrawn
|
|
650 |
||
651 |
call reset_view |
|
652 |
||
653 |
call glClear(ior(GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT)) |
|
654 |
call glCallList(1) |
|
655 |
call glutSwapBuffers |
|
656 |
||
657 |
return
|
|
658 |
end subroutine display |
|
659 |
||
660 |
subroutine draw_func |
|
661 |
real(GLDOUBLE) :: gridx(0:ngridx),gridy(0:ngridy),zval(0:ngridy,2) |
|
662 |
integer :: i,j,k,cont |
|
663 |
real(GLDOUBLE) :: x1,x2,x3,xt,y1,y2,y3,yt,z1,z2,z3,zt |
|
664 |
real(GLDOUBLE) :: frac,xcross1,xcross2,ycross1,ycross2 |
|
665 |
real(GLDOUBLE) :: contour_value(num_contour) |
|
666 |
real(GLFLOAT) :: color(4), normal(3), & |
|
667 |
red(4) = (/1.0,0.0,0.0,1.0/), & |
|
668 |
black(4) = (/0.0,0.0,0.0,1.0/), & |
|
669 |
white(4) = (/1.0,1.0,1.0,1.0/) |
|
670 |
real(GLDOUBLE), external :: func_to_plot |
|
671 |
||
672 |
! prepare to make a new display list
|
|
673 |
||
674 |
call reset_view |
|
675 |
call glDeleteLists(1_gluint, 1_glsizei) |
|
676 |
call glNewList(1_gluint, gl_compile_and_execute) |
|
677 |
||
678 |
! set the grid points
|
|
679 |
||
680 |
gridx = (/ ((minx + i*(maxx-minx)/ngridx),i=0,ngridx) /) |
|
681 |
gridy = (/ ((miny + i*(maxy-miny)/ngridy),i=0,ngridy) /) |
|
682 |
||
683 |
! if this is the first call and either rainbow coloring of a solid surface
|
|
684 |
! or contours are being drawn, minz and maxz need to be set
|
|
685 |
||
686 |
if (minz == 0.0_GLDOUBLE .and. maxz == 0.0_GLDOUBLE .and. & |
|
687 |
( (draw_surface_solid .and. surface_color == rainbow_surface) .or. & |
|
688 |
draw_contour ) ) then |
|
689 |
do i=0,ngridx |
|
690 |
do j=0,ngridy |
|
691 |
z1 = func_to_plot(gridx(i),gridy(j)) |
|
692 |
minz = min(z1,minz) |
|
693 |
maxz = max(z1,maxz) |
|
694 |
end do
|
|
695 |
end do
|
|
696 |
endif
|
|
697 |
||
698 |
! draw the solid surface
|
|
699 |
||
700 |
if (draw_surface_solid) then |
|
701 |
||
702 |
call glPolygonMode(gl_front_and_back, gl_fill) |
|
703 |
call glBegin(gl_triangles) |
|
704 |
||
705 |
! set the color for a red or white surface. For white, set the lighting
|
|
706 |
! such that there is uniform brightness.
|
|
707 |
||
708 |
if (surface_color == red_surface) then |
|
709 |
call glMaterialfv(gl_front_and_back,gl_ambient_and_diffuse,red) |
|
710 |
elseif (surface_color == white_surface) then |
|
711 |
call glDisable(gl_light0) |
|
712 |
call glLightModelfv(gl_light_model_ambient, (/1.,1.,1.,1./)) |
|
713 |
call glMaterialfv(gl_front_and_back,gl_ambient_and_diffuse,white) |
|
714 |
endif
|
|
715 |
||
716 |
! compute the function values for the first line of points
|
|
717 |
||
718 |
do j=0,ngridy |
|
719 |
zval(j,2) = func_to_plot(gridx(0),gridy(j)) |
|
720 |
end do
|
|
721 |
||
722 |
! for each x grid interval...
|
|
723 |
||
724 |
do i=1,ngridx |
|
725 |
||
726 |
! copy left side function values from the right side of the previous interval
|
|
727 |
||
728 |
zval(:,1) = zval(:,2) |
|
729 |
||
730 |
! compute the function values for the right side of the interval
|
|
731 |
||
732 |
do j=0,ngridy |
|
733 |
zval(j,2) = func_to_plot(gridx(i),gridy(j)) |
|
734 |
end do
|
|
735 |
||
736 |
minz = min(minz,minval(zval)) |
|
737 |
maxz = max(maxz,maxval(zval)) |
|
738 |
||
739 |
! for each y grid interval ...
|
|
740 |
||
741 |
do j=1,ngridy |
|
742 |
||
743 |
! add two triangles to the display list
|
|
744 |
! Before each triangle, set the normal. Before each vertex, set the
|
|
745 |
! color if we're coloring by height
|
|
746 |
||
747 |
normal = normcrossprod((/gridx(i-1),gridx(i),gridx(i)/), & |
|
748 |
(/gridy(j-1),gridy(j-1),gridy(j)/), & |
|
749 |
(/zval(j-1,1),zval(j-1,2),zval(j,2)/)) |
|
750 |
call glNormal3fv(normal) |
|
751 |
if (surface_color == rainbow_surface) then |
|
752 |
call get_rainbow(zval(j-1,1),minz,maxz,color) |
|
753 |
call glMaterialfv(gl_front_and_back,gl_ambient_and_diffuse,color) |
|
754 |
endif
|
|
755 |
call glvertex3d(gridx(i-1),gridy(j-1),zval(j-1,1)) |
|
756 |
if (surface_color == rainbow_surface) then |
|
757 |
call get_rainbow(zval(j-1,2),minz,maxz,color) |
|
758 |
call glMaterialfv(gl_front_and_back,gl_ambient_and_diffuse,color) |
|
759 |
endif
|
|
760 |
call glvertex3d(gridx(i ),gridy(j-1),zval(j-1,2)) |
|
761 |
if (surface_color == rainbow_surface) then |
|
762 |
call get_rainbow(zval(j,2),minz,maxz,color) |
|
763 |
call glMaterialfv(gl_front_and_back,gl_ambient_and_diffuse,color) |
|
764 |
endif
|
|
765 |
call glvertex3d(gridx(i ),gridy(j ),zval(j ,2)) |
|
766 |
normal = normcrossprod((/gridx(i-1),gridx(i-1),gridx(i)/), & |
|
767 |
(/gridy(j),gridy(j-1),gridy(j)/), & |
|
768 |
(/zval(j,1),zval(j-1,1),zval(j,2)/)) |
|
769 |
call glNormal3fv(normal) |
|
770 |
if (surface_color == rainbow_surface) then |
|
771 |
call get_rainbow(zval(j,2),minz,maxz,color) |
|
772 |
call glMaterialfv(gl_front_and_back,gl_ambient_and_diffuse,color) |
|
773 |
endif
|
|
774 |
call glvertex3d(gridx(i ),gridy(j ),zval(j ,2)) |
|
775 |
if (surface_color == rainbow_surface) then |
|
776 |
call get_rainbow(zval(j-1,1),minz,maxz,color) |
|
777 |
call glMaterialfv(gl_front_and_back,gl_ambient_and_diffuse,color) |
|
778 |
endif
|
|
779 |
call glvertex3d(gridx(i-1),gridy(j-1),zval(j-1,1)) |
|
780 |
if (surface_color == rainbow_surface) then |
|
781 |
call get_rainbow(zval(j,1),minz,maxz,color) |
|
782 |
call glMaterialfv(gl_front_and_back,gl_ambient_and_diffuse,color) |
|
783 |
endif
|
|
784 |
call glvertex3d(gridx(i-1),gridy(j ),zval(j ,1)) |
|
785 |
||
786 |
end do
|
|
787 |
end do
|
|
788 |
||
789 |
call glEnd |
|
790 |
||
791 |
! if the surface is white, reset the lighting conditions
|
|
792 |
||
793 |
if (surface_color == white_surface) then |
|
794 |
call glEnable(gl_light0) |
|
795 |
call glLightModelfv(gl_light_model_ambient, (/.5,.5,.5,1./)) |
|
796 |
endif
|
|
797 |
||
798 |
||
799 |
endif ! draw_surface_solid |
|
800 |
||
801 |
! draw the surface grid
|
|
802 |
||
803 |
if (draw_surface_grid) then |
|
804 |
||
805 |
call glPolygonMode(gl_front_and_back, gl_line) |
|
806 |
call glBegin(gl_triangles) |
|
807 |
||
808 |
! draw surface grid in black
|
|
809 |
||
810 |
call glMaterialfv(gl_front_and_back,gl_ambient_and_diffuse,black) |
|
811 |
||
812 |
! compute the function values for the first line of points
|
|
813 |
||
814 |
do j=0,ngridy |
|
815 |
zval(j,2) = func_to_plot(gridx(0),gridy(j)) |
|
816 |
end do
|
|
817 |
||
818 |
! for each x grid interval...
|
|
819 |
||
820 |
do i=1,ngridx |
|
821 |
||
822 |
! copy left side function values from the right side of the previous interval
|
|
823 |
||
824 |
zval(:,1) = zval(:,2) |
|
825 |
||
826 |
! compute the function values for the right side of the interval
|
|
827 |
||
828 |
do j=0,ngridy |
|
829 |
zval(j,2) = func_to_plot(gridx(i),gridy(j)) |
|
830 |
end do
|
|
831 |
||
832 |
minz = min(minz,minval(zval)) |
|
833 |
maxz = max(maxz,maxval(zval)) |
|
834 |
||
835 |
! for each y grid interval ...
|
|
836 |
||
837 |
do j=1,ngridy |
|
838 |
||
839 |
! add two triangles to the display list
|
|
840 |
||
841 |
call glvertex3d(gridx(i-1),gridy(j-1),zval(j-1,1)) |
|
842 |
call glvertex3d(gridx(i ),gridy(j-1),zval(j-1,2)) |
|
843 |
call glvertex3d(gridx(i ),gridy(j ),zval(j ,2)) |
|
844 |
call glvertex3d(gridx(i ),gridy(j ),zval(j ,2)) |
|
845 |
call glvertex3d(gridx(i-1),gridy(j-1),zval(j-1,1)) |
|
846 |
call glvertex3d(gridx(i-1),gridy(j ),zval(j ,1)) |
|
847 |
||
848 |
end do
|
|
849 |
end do
|
|
850 |
||
851 |
call glEnd |
|
852 |
||
853 |
endif ! draw_surface_grid |
|
854 |
||
855 |
! draw the contour plot
|
|
856 |
||
857 |
if (draw_contour) then |
|
858 |
||
859 |
call glPolygonMode(gl_front_and_back, gl_line) |
|
860 |
call glBegin(gl_lines) |
|
861 |
call glNormal3fv((/0.0_glfloat, 0.0_glfloat, 1.0_glfloat/)) |
|
862 |
||
863 |
! draw the domain in black, also sets color to black for black_contour
|
|
864 |
||
865 |
call glMaterialfv(gl_front_and_back,gl_ambient_and_diffuse,black) |
|
866 |
call glVertex3d(minx,miny,0.0_GLDOUBLE) |
|
867 |
call glVertex3d(maxx,miny,0.0_GLDOUBLE) |
|
868 |
call glVertex3d(maxx,miny,0.0_GLDOUBLE) |
|
869 |
call glVertex3d(maxx,maxy,0.0_GLDOUBLE) |
|
870 |
call glVertex3d(maxx,maxy,0.0_GLDOUBLE) |
|
871 |
call glVertex3d(minx,maxy,0.0_GLDOUBLE) |
|
872 |
call glVertex3d(minx,maxy,0.0_GLDOUBLE) |
|
873 |
call glVertex3d(minx,miny,0.0_GLDOUBLE) |
|
874 |
||
875 |
! set the contour values
|
|
876 |
||
877 |
if (contour_values_given) then |
|
878 |
contour_value = actual_contours |
|
879 |
else
|
|
880 |
do i=1,num_contour |
|
881 |
contour_value(i) = minz+(maxz-minz)*(i-1)/real(num_contour-1,GLDOUBLE) |
|
882 |
end do
|
|
883 |
endif |
|
884 |
||
885 |
! compute the function values for the first line of points
|
|
886 |
||
887 |
do j=0,ngridy |
|
888 |
zval(j,2) = func_to_plot(gridx(0),gridy(j)) |
|
889 |
end do
|
|
890 |
||
891 |
! for each x grid interval...
|
|
892 |
||
893 |
do i=1,ngridx |
|
894 |
||
895 |
! copy left side function values from the right side of the previous interval
|
|
896 |
||
897 |
zval(:,1) = zval(:,2) |
|
898 |
||
899 |
! compute the function values for the right side of the interval
|
|
900 |
||
901 |
do j=0,ngridy |
|
902 |
zval(j,2) = func_to_plot(gridx(i),gridy(j)) |
|
903 |
end do
|
|
904 |
||
905 |
minz = min(minz,minval(zval)) |
|
906 |
maxz = max(maxz,maxval(zval)) |
|
907 |
||
908 |
! for each y grid interval ...
|
|
909 |
||
910 |
do j=1,ngridy |
|
911 |
||
912 |
! for two triangles
|
|
913 |
||
914 |
do k=1,2 |
|
915 |
||
916 |
! set the vertices
|
|
917 |
||
918 |
if (k==1) then |
|
919 |
x1 = gridx(i-1); y1 = gridy(j-1); z1 = zval(j-1,1) |
|
920 |
x2 = gridx(i ); y2 = gridy(j-1); z2 = zval(j-1,2) |
|
921 |
x3 = gridx(i ); y3 = gridy(j ); z3 = zval(j ,2) |
|
922 |
else
|
|
923 |
x1 = gridx(i-1); y1 = gridy(j-1); z1 = zval(j-1,1) |
|
924 |
x2 = gridx(i-1); y2 = gridy(j ); z2 = zval(j ,1) |
|
925 |
x3 = gridx(i ); y3 = gridy(j ); z3 = zval(j ,2) |
|
926 |
endif
|
|
927 |
||
928 |
! order the vertices by z value
|
|
929 |
||
930 |
xt = x1; yt = y1; zt = z1 |
|
931 |
if (z2 < z1) then |
|
932 |
xt = x1; yt = y1; zt = z1 |
|
933 |
if (z3 < z1) then |
|
934 |
if (z2 < z3) then |
|
935 |
x1 = x2; y1 = y2; z1 = z2 |
|
936 |
x2 = x3; y2 = y3; z2 = z3 |
|
937 |
else
|
|
938 |
x1 = x3; y1 = y3; z1 = z3 |
|
939 |
endif
|
|
940 |
x3 = xt; y3 = yt; z3 = zt |
|
941 |
else
|
|
942 |
x1 = x2; y1 = y2; z1 = z2 |
|
943 |
x2 = xt; y2 = yt; z2 = zt |
|
944 |
endif
|
|
945 |
elseif (z3 < z1) then |
|
946 |
x1 = x3; y1 = y3; z1 = z3 |
|
947 |
x3 = x2; y3 = y2; z3 = z2 |
|
948 |
x2 = xt; y2 = yt; z2 = zt |
|
949 |
elseif (z3 < z2) then |
|
950 |
xt = x2; yt = y2; zt = z2 |
|
951 |
x2 = x3; y2 = y3; z2 = z3 |
|
952 |
x3 = xt; y3 = yt; z3 = zt |
|
953 |
endif
|
|
954 |
||
955 |
! if z1==z3, the triangle is horizontal and no contours pass through it
|
|
956 |
||
957 |
if (z1==z3) cycle |
|
958 |
||
959 |
! for each contour value
|
|
960 |
||
961 |
do cont = 1,num_contour |
|
962 |
||
963 |
! see if it passes through this triangle
|
|
964 |
||
965 |
if (contour_value(cont) < z1) cycle |
|
966 |
if (contour_value(cont) > z3) exit |
|
967 |
||
968 |
! set the color for contours colored by solution
|
|
969 |
||
970 |
if (contour_color == rainbow_contour) then |
|
971 |
call get_rainbow(contour_value(cont),minz,maxz,color) |
|
972 |
call glMaterialfv(gl_front_and_back,gl_ambient_and_diffuse, & |
|
973 |
color) |
|
974 |
endif
|
|
975 |
||
976 |
! see where it crosses the 1-3 edge
|
|
977 |
||
978 |
frac = (contour_value(cont)-z1)/(z3-z1) |
|
979 |
xcross1 = (1.0_GLDOUBLE - frac)*x1 + frac*x3 |
|
980 |
ycross1 = (1.0_GLDOUBLE - frac)*y1 + frac*y3 |
|
981 |
||
982 |
! see where it crosses one of the other edges
|
|
983 |
||
984 |
if (contour_value(cont) == z2) then |
|
985 |
xcross2 = x2 |
|
986 |
ycross2 = y2 |
|
987 |
elseif (contour_value(cont) < z2) then |
|
988 |
frac = (contour_value(cont)-z1)/(z2-z1) |
|
989 |
xcross2 = (1.0_GLDOUBLE - frac)*x1 + frac*x2 |
|
990 |
ycross2 = (1.0_GLDOUBLE - frac)*y1 + frac*y2 |
|
991 |
else
|
|
992 |
frac = (contour_value(cont)-z2)/(z3-z2) |
|
993 |
xcross2 = (1.0_GLDOUBLE - frac)*x2 + frac*x3 |
|
994 |
ycross2 = (1.0_GLDOUBLE - frac)*y2 + frac*y3 |
|
995 |
endif
|
|
996 |
||
997 |
! add the line segment to the display list
|
|
998 |
||
999 |
call glVertex3d(xcross1,ycross1,0.0_GLDOUBLE) |
|
1000 |
call glVertex3d(xcross2,ycross2,0.0_GLDOUBLE) |
|
1001 |
||
1002 |
end do
|
|
1003 |
end do
|
|
1004 |
end do
|
|
1005 |
end do
|
|
1006 |
||
1007 |
call glEnd |
|
1008 |
||
1009 |
endif ! draw_contour |
|
1010 |
||
1011 |
! finish off display list
|
|
1012 |
||
1013 |
call glEndList |
|
1014 |
call glutPostRedisplay |
|
1015 |
||
1016 |
end subroutine draw_func |
|
1017 |
||
1018 |
subroutine get_rainbow(val,minval,maxval,c) |
|
1019 |
real(GLDOUBLE), intent(in) :: val,maxval,minval |
|
1020 |
real(GLFLOAT), intent(out) :: c(4) |
|
1021 |
||
1022 |
real(GLFLOAT) :: f |
|
1023 |
||
1024 |
if (maxval > minval) then |
|
1025 |
f = (val-minval)/(maxval-minval) |
|
1026 |
else ! probably maxval==minval |
|
1027 |
f = 0.5_glfloat |
|
1028 |
endif
|
|
1029 |
||
1030 |
if (f < .25) then |
|
1031 |
c(1) = 0.0_glfloat |
|
1032 |
c(2) = 4.0_glfloat * f |
|
1033 |
c(3) = 1.0_glfloat |
|
1034 |
c(4) = 1.0_glfloat |
|
1035 |
elseif (f < .5) then |
|
1036 |
c(1) = 0.0_glfloat |
|
1037 |
c(2) = 1.0_glfloat |
|
1038 |
c(3) = 2.0_glfloat - 4.0_glfloat*f |
|
1039 |
c(4) = 1.0_glfloat |
|
1040 |
elseif (f < .75) then |
|
1041 |
c(1) = 4.0_glfloat * f - 2.0_glfloat |
|
1042 |
c(2) = 1.0_glfloat |
|
1043 |
c(3) = 0.0_glfloat |
|
1044 |
c(4) = 1.0_glfloat |
|
1045 |
else
|
|
1046 |
c(1) = 1.0_glfloat |
|
1047 |
c(2) = 4.0_glfloat - 4.0_glfloat*f |
|
1048 |
c(3) = 0.0_glfloat |
|
1049 |
c(4) = 1.0_glfloat |
|
1050 |
endif
|
|
1051 |
||
1052 |
end subroutine get_rainbow |
|
1053 |
||
1054 |
function normcrossprod(x,y,z) |
|
1055 |
real(glfloat), dimension(3) :: normcrossprod |
|
1056 |
real(gldouble), dimension(3), intent(in) :: x,y,z |
|
1057 |
real(glfloat) :: t1(3),t2(3),norm |
|
1058 |
t1(1) = x(2) - x(1) |
|
1059 |
t1(2) = y(2) - y(1) |
|
1060 |
t1(3) = z(2) - z(1) |
|
1061 |
t2(1) = x(3) - x(1) |
|
1062 |
t2(2) = y(3) - y(1) |
|
1063 |
t2(3) = z(3) - z(1) |
|
1064 |
normcrossprod(1) = t1(2)*t2(3) - t1(3)*t2(2) |
|
1065 |
normcrossprod(2) = t1(3)*t2(1) - t1(1)*t2(3) |
|
1066 |
normcrossprod(3) = t1(1)*t2(2) - t1(2)*t2(1) |
|
1067 |
norm = sqrt(dot_product(normcrossprod,normcrossprod)) |
|
1068 |
if (norm /= 0._glfloat) normcrossprod = normcrossprod/norm |
|
1069 |
end function normcrossprod |
|
1070 |
||
1071 |
subroutine menu_handler2(selection) bind(c,name="") |
|
1072 |
integer(kind=glcint), value :: selection |
|
1073 |
||
1074 |
select case (selection) |
|
1075 |
||
1076 |
case (surfgrid_toggle) |
|
1077 |
draw_surface_grid = .not. draw_surface_grid |
|
1078 |
call draw_func |
|
1079 |
||
1080 |
case (surfsolid_toggle) |
|
1081 |
draw_surface_solid = .not. draw_surface_solid |
|
1082 |
call draw_func |
|
1083 |
||
1084 |
case (contour_toggle) |
|
1085 |
draw_contour = .not. draw_contour |
|
1086 |
call draw_func |
|
1087 |
||
1088 |
case (quit_selected) |
|
1089 |
stop
|
|
1090 |
||
1091 |
end select
|
|
1092 |
||
1093 |
return
|
|
1094 |
end subroutine menu_handler2 |
|
1095 |
||
1096 |
subroutine param_handler(selection) bind(c,name="") |
|
1097 |
integer(kind=glcint), value :: selection |
|
1098 |
||
1099 |
select case (selection) |
|
1100 |
||
1101 |
case (set_nx) |
|
1102 |
print *,"Enter number of x subintervals:" |
|
1103 |
read *, ngridx |
|
1104 |
call draw_func |
|
1105 |
||
1106 |
case (set_ny) |
|
1107 |
print *,"Enter number of y subintervals:" |
|
1108 |
read *, ngridy |
|
1109 |
call draw_func |
|
1110 |
||
1111 |
case (set_ncontour) |
|
1112 |
print *,"Enter number of contour lines:" |
|
1113 |
read *, num_contour |
|
1114 |
contour_values_given = .false. |
|
1115 |
call draw_func |
|
1116 |
||
1117 |
case (set_contour_val) |
|
1118 |
print *,"enter number of contours:" |
|
1119 |
read *, num_contour |
|
1120 |
if (allocated(actual_contours)) deallocate(actual_contours) |
|
1121 |
allocate(actual_contours(num_contour)) |
|
1122 |
print *,"enter ",num_contour," contour values:" |
|
1123 |
read *,actual_contours |
|
1124 |
contour_values_given = .true. |
|
1125 |
call draw_func |
|
1126 |
||
1127 |
case (set_xrange) |
|
1128 |
print *,"Enter minimum and maximum x values:" |
|
1129 |
read *,minx,maxx |
|
1130 |
call draw_func |
|
1131 |
||
1132 |
case (set_yrange) |
|
1133 |
print *,"Enter minimum and maximum y values:" |
|
1134 |
read *,miny,maxy |
|
1135 |
call draw_func |
|
1136 |
||
1137 |
case (reset_params) |
|
1138 |
ngridx = init_ngridx |
|
1139 |
ngridy = init_ngridy |
|
1140 |
num_contour = init_num_contour |
|
1141 |
contour_color = init_contour_color |
|
1142 |
surface_color = init_surface_color |
|
1143 |
minx = init_minx |
|
1144 |
maxx = init_maxx |
|
1145 |
miny = init_miny |
|
1146 |
maxy = init_maxy |
|
1147 |
draw_surface_grid = init_draw_surface_grid |
|
1148 |
draw_surface_solid = init_draw_surface_solid |
|
1149 |
draw_contour = init_draw_contour |
|
1150 |
call draw_func |
|
1151 |
||
1152 |
end select
|
|
1153 |
||
1154 |
end subroutine param_handler |
|
1155 |
||
1156 |
subroutine contour_color_handler(selection) bind(c,name="") |
|
1157 |
integer(kind=glcint), value :: selection |
|
1158 |
||
1159 |
contour_color = selection |
|
1160 |
call draw_func |
|
1161 |
||
1162 |
end subroutine contour_color_handler |
|
1163 |
||
1164 |
subroutine surface_color_handler(selection) bind(c,name="") |
|
1165 |
integer(kind=glcint), value :: selection |
|
1166 |
||
1167 |
surface_color = selection |
|
1168 |
call draw_func |
|
1169 |
||
1170 |
end subroutine surface_color_handler |
|
1171 |
||
1172 |
subroutine make_menu(submenuid) |
|
1173 |
integer, intent(in) :: submenuid |
|
1174 |
integer :: menuid, param_id, contour_color_menu, surface_color_menu |
|
1175 |
||
1176 |
contour_color_menu = glutCreateMenu(contour_color_handler) |
|
1177 |
call glutAddMenuEntry("black"//char(0),black_contour) |
|
1178 |
call glutAddMenuEntry("contour value"//char(0),rainbow_contour) |
|
1179 |
||
1180 |
surface_color_menu = glutCreateMenu(surface_color_handler) |
|
1181 |
call glutAddMenuEntry("red"//char(0),red_surface) |
|
1182 |
call glutAddMenuEntry("white"//char(0),white_surface) |
|
1183 |
call glutAddMenuEntry("surface height"//char(0),rainbow_surface) |
|
1184 |
||
1185 |
param_id = glutCreateMenu(param_handler) |
|
1186 |
call glutAddMenuEntry("number of x grid intervals"//char(0),set_nx) |
|
1187 |
call glutAddMenuEntry("number of y grid intervals"//char(0),set_ny) |
|
1188 |
call glutAddMenuEntry("number of uniform contour lines"//char(0),set_ncontour) |
|
1189 |
call glutAddMenuEntry("contour values"//char(0),set_contour_val) |
|
1190 |
call glutAddMenuEntry("x range"//char(0),set_xrange) |
|
1191 |
call glutAddMenuEntry("y range"//char(0),set_yrange) |
|
1192 |
call glutAddSubMenu("contour color"//char(0),contour_color_menu) |
|
1193 |
call glutAddSubMenu("surface color"//char(0),surface_color_menu) |
|
1194 |
call glutAddMenuEntry("reset to initial parameters"//char(0),reset_params) |
|
1195 |
||
1196 |
menuid = glutCreateMenu(menu_handler2) |
|
1197 |
call glutAddSubMenu("View Modifier"//char(0),submenuid) |
|
1198 |
call glutAddMenuEntry("toggle surface grid"//char(0),surfgrid_toggle) |
|
1199 |
call glutAddMenuEntry("toggle solid surface"//char(0),surfsolid_toggle) |
|
1200 |
call glutAddMenuEntry("toggle contour"//char(0),contour_toggle) |
|
1201 |
call glutAddSubMenu("plotting parameters"//char(0),param_id) |
|
1202 |
call glutAddMenuEntry("quit"//char(0),quit_selected) |
|
1203 |
call glutAttachMenu(GLUT_RIGHT_BUTTON) |
|
1204 |
end subroutine make_menu |
|
1205 |
||
1206 |
end module function_plotter |
|
1207 |
||
1208 |
!---------------------------------------------------------------------------
|
|
1209 |
||
1210 |
program plot_func |
|
1211 |
||
1212 |
use opengl_gl |
|
1213 |
use opengl_glut |
|
1214 |
use view_modifier |
|
1215 |
use function_plotter |
|
1216 |
implicit none
|
|
1217 |
||
1218 |
integer :: winid, menuid, submenuid |
|
1219 |
||
1220 |
! Initializations
|
|
1221 |
||
1222 |
call glutInit |
|
1223 |
call glutInitDisplayMode(ior(GLUT_DOUBLE,ior(GLUT_RGB,GLUT_DEPTH))) |
|
1224 |
call glutInitWindowSize(500_glcint,500_glcint) |
|
1225 |
||
1226 |
! Create a window
|
|
1227 |
||
1228 |
winid = glutCreateWindow("Function plotter") |
|
1229 |
||
1230 |
! initialize view_modifier, receiving the id for it's submenu
|
|
1231 |
||
1232 |
submenuid = view_modifier_init() |
|
1233 |
||
1234 |
! create the menu
|
|
1235 |
||
1236 |
call make_menu(submenuid) |
|
1237 |
||
1238 |
! Set the display callback
|
|
1239 |
||
1240 |
call glutDisplayFunc(display) |
|
1241 |
||
1242 |
! set the lighting conditions
|
|
1243 |
||
1244 |
call glClearColor(0.9_glclampf, 0.9_glclampf, 0.9_glclampf, 1.0_glclampf) |
|
1245 |
call glLightfv(gl_light0, gl_diffuse, (/1.,1.,1.,1./)) |
|
1246 |
call glLightfv(gl_light0, gl_position, (/1.5,-.5,2.,0.0/)) |
|
1247 |
call glEnable(gl_lighting) |
|
1248 |
call glEnable(gl_light0) |
|
1249 |
call glLightModelfv(gl_light_model_ambient, (/.5,.5,.5,1./)) |
|
1250 |
call glDepthFunc(gl_lequal) |
|
1251 |
call glEnable(gl_depth_test) |
|
1252 |
||
1253 |
! Create the image
|
|
1254 |
||
1255 |
call draw_func |
|
1256 |
||
1257 |
! Let glut take over
|
|
1258 |
||
1259 |
call glutMainLoop |
|
1260 |
||
1261 |
end program plot_func |
|
1262 |
||
1263 |
!---------------------------------------------------------------------------
|
|
1264 |
||
1265 |
! The function to plot
|
|
1266 |
||
1267 |
function func_to_plot(x,y) |
|
1268 |
use opengl_gl |
|
1269 |
real(GLDOUBLE) :: func_to_plot |
|
1270 |
real(GLDOUBLE), intent(in) :: x,y |
|
1271 |
||
1272 |
func_to_plot = 0.5_GLDOUBLE * ( & |
|
1273 |
cos(0.3_GLDOUBLE*sqrt(80.0_GLDOUBLE*x)-16.0_GLDOUBLE*y/3.0_GLDOUBLE)* & |
|
1274 |
cos(16.0_GLDOUBLE*x/3.0_GLDOUBLE) + x-y ) |
|
1275 |
||
1276 |
end function func_to_plot |