; docformat = 'rst' ;+ ; Handle all the events generated by this widget program. ; ; :Params: ; event : in, required, type=structure ; event structure ;- pro mg_surfview_event, event compile_opt strictarr widget_control, event.top, get_uvalue=pstate uname = widget_info(event.id, /uname) case uname of 'tlb' : begin ; collect geometry information tlbG = widget_info(event.top, /geometry) ; calculate new draw widget size new_x = event.x - 2 * tlbG.xpad new_y = event.y - 2 * tlbG.ypad ; set draw widget size widget_control, (*pstate).draw, xsize=new_x, ysize=new_y ; refresh graphics (*pstate).owindow->draw, (*pstate).oview ; reset trackball for the new size draw widget (*pstate).otrack->reset, [new_x, new_y] / 2, (new_x > new_y) / 2 end 'draw' : begin ; motion and button events must be sent to trackball; it will set update ; if the model needs to be rotated update = (*pstate).otrack->update(event, transform=rotation) if update then begin (*pstate).omodel->getProperty, transform=transform (*pstate).omodel->setProperty, transform=transform # rotation (*pstate).owindow->draw, (*pstate).oview endif end endcase end ;+ ; Free resources saved in the state structure. ; ; :Params: ; tlb : in, required, type=long ; widget ID of the top-level base ;- pro mg_surfview_cleanup, tlb compile_opt strictarr widget_control, tlb, get_uvalue=pstate obj_destroy, [(*pstate).otrack, (*pstate).oview] ptr_free, pstate end ;+ ; Widget program to display and interact with surface using object graphics. ; ; :Params: ; z : in, optional, type="fltarr(m, n)" ; z-values for surface ; ; :Keywords: ; renderer : in, optional, type=long ; set to 0 for hardware rendering, 1 for software rendering ;- pro mg_surfview, z, renderer=renderer compile_opt strictarr ; default data for convenience during development _z = n_elements(z) eq 0 ? hanning(20, 20) : z xsize = 400 ysize = 400 ; create widget hierarchy tlb = widget_base(title='Surface view', /column, $ /tlb_size_events, uname='tlb') draw = widget_draw(tlb, xsize=xsize, ysize=ysize, $ graphics_level=2, renderer=renderer, $ ; 2 => object graphics /motion_events, /button_events, uname='draw') widget_control, tlb, /realize ; Because of the GRAPHICS_LEVEL=2 in the WIDGET_DRAW creation the value for ; the draw widget will be an IDLgrWindow object reference. widget_control, draw, get_value=owindow ; create object graphics oview = obj_new('IDLgrView', color=[0, 0, 0]) omodel = obj_new('IDLgrModel') oview->add, omodel ; style = 2 is filled osurface = obj_new('IDLgrSurface', _z, style=2, $ color=[255, 0, 0], bottom=[100, 0, 0]) omodel->add, osurface olightmodel = obj_new('IDLgrModel') oview->add, olightmodel ; type = 2 is a directional light; shines from [-1, 1, 1] to [0, 0, 0] olight = obj_new('IDLgrLight', type=2, location=[-1, 1, 1]) olightmodel->add, olight ; the following creates the scaling functions to transform between data space ; and the default view volume of -1 to +1 in each direction osurface->getProperty, xrange=xr, yrange=yr, zrange=zr xc = norm_coord(xr) xc[0] -= 0.5 yc = norm_coord(yr) yc[0] -= 0.5 zc = norm_coord(zr) zc[0] -= 0.5 osurface->setProperty, xcoord_conv=xc, ycoord_conv=yc, zcoord_conv=zc ; set a nice original orientation omodel->rotate, [1, 0, 0], -90 omodel->rotate, [0, 1, 0], -30 omodel->rotate, [1, 0, 0], 30 owindow->draw, oview otrack = obj_new('Trackball', [xsize, ysize] / 2, (xsize > ysize) / 2) ; setup state structure state = { oview: oview, $ omodel: omodel, $ owindow: owindow, $ otrack: otrack, $ draw: draw $ } pstate = ptr_new(state, /no_copy) widget_control, tlb, set_uvalue=pstate ; start XMANAGER xmanager, 'mg_surfview', tlb, /no_block, $ event_handler='mg_surfview_event', $ cleanup='mg_surfview_cleanup' end