;+--------------------------------------------------------------------------- ; CLASSNAME: SelectMap ; ; AUTHOR: ; Antonio Santiago Perez ; (http://asantiago.gentelibre.org) ; ; DESCRIPTION: ; Show a background image and make line selection. The ; coordenates of initial/final points of the line seleccion are ; returned normalized respect widget and image size. ; ; METHODS: ; ; ; HISTORY: ; ; Mon Nov 15 17:44:54 2004, Antonio Santiago ; ; ;---------------------------------------------------------------------------- PRO SelectMap__define struct = { SelectMap, $ INHERITS EventAction, $ parent_id: 0L, $ ;Parent widget base_id: 0L, $ ;WIDGET_BASE of the object. widget_id: 0L, $ ;WIDGET_DRAW inside widget_base. oWindow: OBJ_NEW(), $ ;The window oView: OBJ_NEW(), $ ;The view oModel: OBJ_NEW(), $ ;The model oImage: OBJ_NEW(), $ ;Background image oPalette: OBJ_NEW(), $ ;Palette for the image oSelectLine: OBJ_NEW(), $ ;Selection line size: [0., 0.], $ ;Widget draw size map_size: [0., 0.], $ ;Image size ;;Line selection line_sel: [[0.,0.], [0.,0.]], $ ;Initial/final poinst of the ;selected line with coordenates respect ;widget_draw size. line_map_sel: [[0.,0.], [0.,0.]], $ ;Initial/final points of the ;selected line with coordenates respect ;image size. ;;Square selection square_sel: [[0.,0.], [0.,0.], $ ;Initial/final poinst of the [0.,0.], [0.,0.]], $ ;selected square with ;coordenates respect ;widget_draw size. square_map_sel: [[0.,0.], [0.,0.], $ ;Initial/final points of the [0.,0.], [0.,0.]], $ ;selected square with ;coordenates respect ;image size. selectionType: '', $ ;Specifies the selection type: LINE/SQUARE bSelecting: 0B, $ ;Are we making a selection? bHideSelection: 0B, $ ;Is visible the selection line? bDynamicSelection: 0B $ ;Emit SELECTION signals when we are ;making the selection? } END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::Init ; ; DESCRIPTION: ; Creates an instance of 'SelectMap' class. ; ; PARAMETERS: ; parent - Parents widget ID. ; ; EXTRA PARAMETERS: ; extra - Extra KEYWORD with options to be passed to the ; widget_draw. ; ;---------------------------------------------------------------------------- FUNCTION SelectMap::Init, parent, _EXTRA=extra ;;Initilize superclass result = self->EventAction::Init() IF NOT KEYWORD_SET(parent) THEN RETURN, 0 ;;Create widget and object hieriarchy. wBase = WIDGET_BASE(parent) wDraw = WIDGET_DRAW(wBase, GRAPHICS_LEVEL=2, /EXPOSE_EVENTS, $ /BUTTON_EVENTS, /MOTION_EVENTS, _EXTRA=extra, $ UVALUE={class_name: 'SelectMap', object: self, $ handler: 'EventHandler'}) self.parent_id = parent self.base_id = wBase self.widget_id = wDraw ;;Register the 'event' of the class self->AddEvent, 'SELECTION' self->AddEvent, 'MOTION' self->Initialize RETURN, 1 END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::Initialize ; ; DESCRIPTION: ; Initialize the state of the object. If it is executed when the ; object is running the object's state goes back to the same as ; the creation state. All possible used memory are free. ; ;---------------------------------------------------------------------------- PRO SelectMap::Initialize ;;Free memory usage self->Clear ;;Realize the WIDGET_BASE and get the IDLgrWindow object from, ;;WIDGET_DRAW WIDGET_CONTROL, self.base_id , /REALIZE WIDGET_CONTROL, self.widget_id, GET_VALUE=oWindow oWindow->SetProperty, QUALITY=0 oView = OBJ_NEW('IDLgrView', ZCLIP=[0.2,-0.2], $ VIEWPLANE_RECT=[0,0,1,1], COLOR=[50,50,70]) oModel = OBJ_NEW('IDLgrModel') oLight = OBJ_NEW('IDLgrLight', TYPE=1, LOCATION=[0,0,12], $ INTENSITY=0.95) ;;Initialize attributes geom = WIDGET_INFO(self.widget_id, /GEOMETRY) self.size = [geom.xsize, geom.ysize] self.map_size = [0., 0.] self.line_sel = [[0.,0.], [0.,0.]] self.line_map_sel = [[0.,0.], [0.,0.]] self.selectionType = 'SQUARE' self.bHideSelection = 0 ;Hide selection self.bDynamicSelection = 0 ;No dynamic selection self.bSelecting = 0 ;;Save references to the objects oView->Add, oModel oModel->Add, oLight self.oWindow = oWindow self.oView = oView self.oModel = oModel END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::Cleanup ; ; DESCRIPTION: ; Free memory used by the object. ; ;---------------------------------------------------------------------------- PRO SelectMap::Cleanup OBJ_DESTROY, [self.oWindow] self->Clear self->EventAction::Cleanup END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::Clear ; ; DESCRIPTION: ; Free memory used by the object. ; ;---------------------------------------------------------------------------- PRO SelectMap::Clear ;;When destroy de IDLgrView the IDLgrModel are destroyed with all ;;its contents, included the image and seleccion line. OBJ_DESTROY, [self.oView, self.oPalette, self.oSelectLine] END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::SetPalette ; ; DESCRIPTION: ; Sets a color palette used to show bachground image. Only takes ; efect if the background image is a X,Y array. ; ; PARAMETERS: ; colors - 256x3 array values (RGB). ; ;---------------------------------------------------------------------------- PRO SelectMap::SetPalette, colors ;;Destroy the last palette (if exists) OBJ_DESTROY, self.oPalette oPalette = OBJ_NEW('IDLgrPalette', colors[*,0], colors[*,1], colors[*,2]) ;;Save reference to the palette. self.oPalette = oPalette END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::SetMap ; ; DESCRIPTION: ; Sets a background image. The image can be a (x,y) array that ; will be colored with the specified palette or may be a ; (3,x,y), (x,3,y) or (x,y,3) array (like an 'jpeg' image). ; ; PARAMETERS: ; data_map - Array 2D or 3D with the image to show. ; ;---------------------------------------------------------------------------- PRO SelectMap::SetMap, data_map ;;Destroy previeus objects. OBJ_DESTROY, [self.oImage, self.oSelectLine] ;;Get dimension of the image and calcula the normalization factors ;;depending on the type of the image. sizes = SIZE(data_map, /DIMENSIONS) IF N_ELEMENTS(sizes) EQ 3 THEN BEGIN ;;Image 3,X,Y IF sizes[0] LE 4 THEN BEGIN xsize = sizes[1] ysize = sizes[2] xconv = NORMALIZE([0, xsize-1], Position=[0,1]) yconv = NORMALIZE([0, ysize-1], Position=[0,1]) ENDIF ;;Image X,3,Y IF sizes[1] LE 4 THEN BEGIN xsize = sizes[0] ysize = sizes[2] xconv = NORMALIZE([0, xsize-1], Position=[0,1]) yconv = NORMALIZE([0, ysize-1], Position=[0,1]) ENDIF ;;Image X,Y,3 IF sizes[2] LE 4 THEN BEGIN xsize = sizes[0] ysize = sizes[1] xconv = NORMALIZE([0, xsize-1], Position=[0,1]) yconv = NORMALIZE([0, ysize-1], Position=[0,1]) ENDIF ENDIF ELSE BEGIN ;;Image X,Y xsize = sizes[0] ysize = sizes[1] xconv = NORMALIZE([0, xsize-1], Position=[0,1]) yconv = NORMALIZE([0, ysize-1], Position=[0,1]) ENDELSE ;;Save the dimensions of the image. self.map_size = [xsize, ysize] ;;Create the image as a texture of polygon. oImage = OBJ_NEW('IDLgrImage', data_map, PALETTE=self.oPalette, $ XCOORD_CONV=xconv, YCOORD_CONV=yconv) ;;Create the selection line object IF self.selectionType EQ 'LINE' THEN BEGIN connect_line = [2, 0, 1] oSelectLine = OBJ_NEW('IDLgrPolyline', self.line_map_sel, $ POLYLINES=connect_line, $ COLOR=[150,150,150], THICK=2, $ HIDE=self.bHideSelection, $ XCOORD_CONV=xconv, YCOORD_CONV=yconv) ENDIF ELSE BEGIN connect_line = [4, 0, 1, 2, 3] oSelectLine = OBJ_NEW('IDLgrPolyline', self.square_map_sel, $ POLYLINES=connect_line, $ COLOR=[150,150,150], THICK=2, $ HIDE=self.bHideSelection, $ XCOORD_CONV=xconv, YCOORD_CONV=yconv) ENDELSE ;;Save object references self.oModel->Add, oImage self.oModel->Add, oSelectLine self.oImage = oImage self.oSelectLine = oSelectLine END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::Draw ; ; DESCRIPTION: ; Draws the object. ; ;---------------------------------------------------------------------------- PRO SelectMap::Draw self.oWindow->Draw, self.oView END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::GetProperty ; ; DESCRIPTION: ; Get the the properties of the object. ; ; KEYWORD PARAMETERS: ; id - ID of the WIDGET_BASE over the object are created. ; ;---------------------------------------------------------------------------- PRO SelectMap::GetProperty, ID=id id = self.base_id END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::SetProperty ; ; DESCRIPTION: ; Sets the properties of the object. ; ; KEYWORD PARAMETERS: ; hide_selection - Show/hide the selection line. ; dynamic_selection - If true, SELECTION events are emited while a ; selecction is doing. ; ;---------------------------------------------------------------------------- PRO SelectMap::SetProperty, $ SELECTION_TYPE=selection_type, $ DYNAMIC_SELECTION=dynamic_selection, $ HIDE_SELECTION=hide_selection IF selection_type EQ 'LINE' OR selection_type EQ 'SQUARE' THEN BEGIN self.selectionType = selection_type ENDIF IF N_ELEMENTS(dynamic_selection) THEN BEGIN self.bDynamicSelection = dynamic_selection ENDIF IF N_ELEMENTS(hide_selection) THEN BEGIN self.bHideSelection = hide_selection self.oSelectLine->SetProperty, HIDE=hide_selection ENDIF END ;+--------------------------------------------------------------------------- ; NAME: SelectMap_EventHandler ; ; DESCRIPTION: ; Object's event handler. ; ;---------------------------------------------------------------------------- PRO SelectMap::EventHandler, event ;;Expose Event IF event.type EQ 4 THEN BEGIN self->Draw ENDIF ;;Mouse down button IF (event.type EQ 0) AND (event.press EQ 1) THEN BEGIN IF NOT self.bHideSelection THEN BEGIN ;;Set that a selection is doing self.bSelecting = 1 ;;Update the line coordenates self->UpdateLineSelection, event, /ALL self->UpdateSquareSelection, event, /ALL IF self.selectionType EQ 'LINE' THEN BEGIN connect_line = [2, 0, 1] self.oSelectLine->SetProperty, DATA=self.line_map_sel, $ COLOR=[255,255,0], POLYLINE=connect_line ENDIF ELSE BEGIN connect_line = [4, 0, 1, 2, 3] self.oSelectLine->SetProperty, DATA=self.square_map_sel, $ COLOR=[255,255,0], POLYLINE=connect_line ENDELSE ENDIF ENDIF ;;Mouse up button IF (event.type EQ 1) AND (event.release EQ 1)THEN BEGIN ;;Set that the selection are finished self.bSelecting = 0 ;;Update the line corrdenates. self->UpdateLineSelection, event self->UpdateSquareSelection, event IF self.selectionType EQ 'LINE' THEN BEGIN self.oSelectLine->SetProperty, DATA=self.line_map_sel, $ COLOR=[255,255,255] ENDIF ELSE BEGIN self.oSelectLine->SetProperty, DATA=self.square_map_sel, $ COLOR=[255,255,255] ENDELSE ;;Generate a 'SELECTION' event. self->Draw self->EmitEvent, 'SELECTION', $ EVENT_STRUCT={line_sel: self.line_sel, $ line_map_sel: self.line_map_sel} ENDIF ;;Mouse move IF (event.type EQ 2) THEN BEGIN ;;If a selection is doing actualize the coordenates. IF self.bSelecting THEN BEGIN self->UpdateLineSelection, event self->UpdateSquareSelection, event IF self.selectionType EQ 'LINE' THEN BEGIN self.oSelectLine->SetProperty, DATA=self.line_map_sel ENDIF ELSE BEGIN self.oSelectLine->SetProperty, DATA=self.square_map_sel ENDELSE self->Draw ENDIF ;;Generate a 'MOTION' event. values = [event.x, event.y] convert = self->ConvertValuesW2M(values) self->EmitEvent, 'MOTION', $ EVENT_STRUCT={ point_sel: values, $ point_map_sel: convert } ENDIF END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::UpdateLineSelection ; ; DESCRIPTION: ; Get the actual coordenate points and convert respect the image ; size. ; ; KEYWORD PARAMETERS: ; all - If set specify that the two points (origin, final) of ; the selection line must to be initialize. If not set, ; only the final point is converted. ; ; NOTE: The 0 and 2 points of the square are the initial and final ; points respectively. ; ;---------------------------------------------------------------------------- PRO SelectMap::UpdateLineSelection, event, ALL=all xpoint = (event.x > 0) < (self.size[0]-1) ypoint = (event.y > 0) < (self.size[1]-1) IF KEYWORD_SET(all) THEN BEGIN self.line_sel[*,0] = [xpoint, ypoint] self.line_map_sel[*,0] = self->ConvertValuesW2M(self.line_sel[*,0]) ENDIF self.line_sel[*,1] = [xpoint, ypoint] self.line_map_sel[*,1] = self->ConvertValuesW2M(self.line_sel[*,1]) END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::UpdateSquareSelection ; ; DESCRIPTION: ; Get the actual coordenate points and convert respect the image ; size. ; ; KEYWORD PARAMETERS: ; all - If set specify that the two points (origin, final) of ; the selection line must to be initialize. If not set, ; only the final point is converted. ; ; NOTE: The 0 and 2 points of the square are the initial and final ; points respectively. ; ;---------------------------------------------------------------------------- PRO SelectMap::UpdateSquareSelection, event, ALL=all xpoint = (event.x > 0) < (self.size[0]-1) ypoint = (event.y > 0) < (self.size[1]-1) IF KEYWORD_SET(all) THEN BEGIN ;;Initial point self.square_sel[*,0] = [xpoint, ypoint] self.square_map_sel[*,0] = self->ConvertValuesW2M([xpoint, ypoint]) ENDIF ;;Final point self.square_sel[*,2] = [xpoint, ypoint] self.square_map_sel[*,2] = self->ConvertValuesW2M([xpoint, ypoint]) ;;Other points xinit = self.square_sel[0,0] yinit = self.square_sel[1,0] width = xinit - xpoint height = yinit - ypoint self.square_sel[*,1] = [(xinit + width), ypoint] self.square_map_sel[*,1] = self->ConvertValuesW2M([xpoint, ypoint]) self.square_sel[*,3] = [xpoint, (ypoint + height)] self.square_map_sel[*,3] = self->ConvertValuesW2M([xpoint, ypoint]) END ;+--------------------------------------------------------------------------- ; NAME: SelectMap::ConvertValuesW2M ; ; DESCRIPTION: ; Convert a pair of values from widget size relative coordenatos ; to the image relativa size coordenates. ; ;---------------------------------------------------------------------------- FUNCTION SelectMap::ConvertValuesW2M, values values[0] = (values[0] > 0) < (self.size[0]-1) values[1] = (values[1] > 0) < (self.size[1]-1) convert = values convert[0] = values[0] * (self.map_size[0]-1) / (self.size[0]-1) convert[1] = values[1] * (self.map_size[1]-1) / (self.size[1]-1) RETURN, convert END