; This is version 4.0 ; Change from version 3.6 : Corrected a bug limited the number of directions to 14 (should be 16 for Parasol) ; Change from version 3.5 : Corrected a bug that applied only to IDL on Windows systems ; Change from version 3.4 : Add product L2TLGV. Aerosol and surface signatures over land. Added common L2TLGV ; Change from version 3.3 : Change to cope with the modifications of L2TOGV product. Added the common ; COM_L2TOGV that gives the position of the variables of interest to be ploted ; Change from version 3.2 : Added the extraction of level-1 DQX. Add the "text save" option ; Change from version 3.1 : Fix the positions of windows. Fixed a small bug that lead to unecessary memory use. ; Change from version 3.0: Add a routine to plot the comparison of aerosol reflectance measured and modeled, from the Level2 "suivi" file ; Change from version 2.2: Compatible wwith both POLDER dand Parasol files (number of directions from 14 to 16, a few other changes) ; CHANGES FROM VERSION 2.1 ; Changed file selection so that filenames with extensions (ie longer than 16 characters), that result from spatial ; extractions, may be used by Anapol ; Corrected a bug that lead to eroneous map overlay in very specific conditions ; When ploting directional signatures; does not assign negative angles when the min angle is close to zero ; CHANGES FROM VERSION 1.12 ; Add option to save HDF-EOS files ;-------------------------------------------------------------------------- ; CHANGES FROM VERSION 1.11 ; When ploting signatures; does not assign negative angles when the min angle is close to zero ; CHANGES FROM VERSION 1.10 ; Changed User/Auto Button ; Corrected an improper FORWARD_FUNCTION call ; CHANGES FROM VERSION 1.9 ; Read infos on one bit (Data Quality Information) ; Correct a bug that lead to a Crash when Pixel Info Window was closed by the user ; CHANGES FROM VERSION 1.8 ; Possibility to read parameters coded on 1/2 bytes ; CHANGES FROM VERSION 1.7 ; Corrected a bug that lead to crash when there were no valid parameters in the selected zone ; Corrected a bug on the display when there is a single valid value ; /NO_BLOCK option so that anapol can be run together with other applications ; When change of selected parameter, and new unit is different than the old, return to automatic scaling ; Added lin and column information in the "Data values" window ==> POLDER validation users ; CHANGES FROM VERSION 1.6 ; define products are now separate routines ; Both Class 1 and Class 2 products can be read ; CHANGES FROM VERSION 1.5 ; Add Polarization Direction information in Level 1 product ; Change structure of "extract" routine ;---------------------------- ; CHANGES FROM VERSION 1.4 ;Add (line/col) information on the position window ;---------------------------- ; CHANGES FROM VERSION 1.3 ;Display isolines of angles only for Level 1 ; Commenc� a mettre la possibilte de sauver les HDF ; Virer l'appel a la fonction FILE_TEXT (n'existe pas en IDL 5.2) ; CHANGES FROM VERSION 1.2 ;Correction of a bug tat prevented the dispaly of some data close to the 180� line ;Correction of the display of the selected area (when the area goes over the limit of the Earth close to the Pole) ;========================================================================================= ; ����� HELPMENU_EVENT ����� ; Lecture et display du fichier help ;----------------------------------------------------------------------------------------- PRO HelpMenu_Event,event WIDGET_CONTROL,event.top,GET_UVALUE=pstate ; ; On verifie que le code trouve le fichier automoatiquement. Sinon, on demande de l'aide, ; et on garde en memoire ou le fichier help a �t� trouv� result = FILE_TEST((*(*pstate).wstrParam).wpathHelp) IF NOT result THEN (*(*pstate).wstrParam).wpathHelp = $ DIALOG_PICKFILE(FILTER='Help_AnaPol.txt',/MUST_EXIST,TITLE='Locate Help File') ; Appel de l'aide XDISPLAYFILE,(*(*pstate).wstrParam).wpathHelp,TITLE='Short Help',DONE_BUTTON='Quit',WIDTH=100 END ; ����� END OF HELPMENU_EVENT ����� ;========================================================================================= ; ����� FILEMENU_EVENT ����� ; Gestion du Exit, et du "save" des fenetres graphiques ;----------------------------------------------------------------------------------------- PRO FileMenu_Event,event FORWARD_FUNCTION define_EOS,line WIDGET_CONTROL,event.top,GET_UVALUE=pstate ; On recupere la uvalue du event.id (=le clic sur open du menu file) WIDGET_CONTROL,event.id,GET_UVALUE=uval ; Rep�rage de toutes les fenetres ouvertes DEVICE, WINDOW_STATE=winstate par = (*pstate).wstrParam prod= (*pstate).wstrProd Tab = (*pstate).wstrTab IF STRMID(uval,0,4) EQ 'save' THEN BEGIN ip = (*par).wchan MOD 100 CASE (*par).wchan /100 OF 0 : name = ((*prod).U_par[ip]).name 1 : name = ((*prod).D_par[ip]).name 2 : name = ((*prod).C_par[ip]).name 3 : name = ((*prod).Cd_par[ip]).name ENDCASE WHILE ip NE -1 DO BEGIN ip = STRPOS(name,' ') IF ip GE 0 THEN STRPUT, name, '_', ip ENDWHILE ENDIF CASE uval OF 'exit': BEGIN ; Destruction de toutes les fen�tres ouvertes FOR id=0,N_ELEMENTS(winstate)-1 DO IF winstate[id] THEN WDELETE,id IF WIDGET_INFO ((*(*pstate).wstrParam).wvdisp,/VALID_ID) THEN $ WIDGET_CONTROL,(*(*pstate).wstrParam).wvdisp,/DESTROY ; Destruction de la TopLevelBase WIDGET_CONTROL,event.top,/DESTROY ; Nettoyage de la Heap Memory HEAP_GC END 'save_view': BEGIN fileout=DIALOG_PICKFILE(/WRITE,TITLE='Select Filename for image file',FILE=name+'.PNG',$ GET_PATH=pathout,PATH=(*par).wpathout) IF STRLEN(fileout) EQ 0 THEN RETURN (*par).wpathout = pathout DEVICE,DECOMPOSE=1 WSET,(*par).wid & imag1 = TVRD(/TRUE) & s1=SIZE(imag1) DEVICE,DECOMPOSE=1 WSET,(*par).wpid & imag2 = TVRD(/TRUE) & s2=SIZE(imag2) center = [INTARR((s1[2]-s2[2]+1)/2),INDGEN(s2[2]),INTARR((s1[2]-s2[2])/2)] imag2 = imag2[*,center,*] WRITE_PNG,fileout,[[[imag1]],[[imag2]]];,/TRUE END 'save_ang': BEGIN IF winstate[5] THEN BEGIN fileout=DIALOG_PICKFILE(/WRITE,TITLE='Select Filename for image file',FILE='Polar_Plot.PNG',$ GET_PATH=pathout,PATH=(*par).wpathout) IF STRLEN(fileout) EQ 0 THEN RETURN (*par).wpathout = pathout WSET,5 WSHOW, 5, ICONIC=0 WRITE_PNG,fileout,TVRD(/TRUE) ENDIF ELSE BEGIN user_response=DIALOG_MESSAGE('The selected graph does not exist.') ENDELSE END 'save_ref': BEGIN IF winstate[4] THEN BEGIN fileout=DIALOG_PICKFILE(/WRITE,TITLE='Select Filename for image file',FILE='Dir_'+Name+'.PNG',$ GET_PATH=pathout,PATH=(*par).wpathout) IF STRLEN(fileout) EQ 0 THEN RETURN (*par).wpathout = pathout WSET,4 WSHOW, 4, ICONIC=0 WRITE_PNG,fileout,TVRD(/TRUE) ENDIF ELSE BEGIN user_response=DIALOG_MESSAGE('The selected graph does not exist.') ENDELSE END 'Text_Save': BEGIN ; Creation et ouverture du fichier texte pour ecriture fileout=DIALOG_PICKFILE(/WRITE,TITLE='Select Filename for text save', FILE='AnaPol_resu.txt', $ GET_PATH=pathout,PATH=(*par).wpathout) IF STRLEN(fileout) EQ 0 THEN RETURN (*par).wpathout = pathout OPENW, lun_out, fileout,/GET_LUN ; Ouverture du fichier dans lequel on ecrit les parapetres PRINTF,lun_out,STRING((*prod).Nu_par+3,format='(I3)' )+' NON-DIRECTIONAL PARAMETERS' PRINTF,lun_out,' line number [ no unit]' PRINTF,lun_out,' column number [ no unit]' FOR i=0, (*prod).Nu_par-1 DO PRINTF,lun_out,(*prod).U_par[i].name,(*prod).U_par[i].unit,format='(A16,2X,"[",A10,"]")' PRINTF,lun_out,'# of valid dire. [ no unit]' IF (*prod).Nd_par GT 0 THEN BEGIN PRINTF,lun_out,STRING((*prod).Nd_par+3,format='(I3)' )+' DIRECTIONAL PARAMETERS' PRINTF,lun_out,'Solar Zenith Ang [ degrees]' PRINTF,lun_out,'View Zenith Angl [ degrees]' PRINTF,lun_out,'Relative Azimuth [ degrees]' FOR i=0, (*prod).Nd_par-1 DO PRINTF,lun_out,(*prod).D_par[i].name,(*prod).D_par[i].unit,format='(A16,2X,"[",A10,"]")' ENDIF val = WHERE((*(*tab).wLin) NE 0, cc) PRINTF,lun_out,STRING(cc,FORMAT='(I3)')+' VALID PIXELS' FOR iy=0, (*par).wnbl-1 DO FOR ix=0, (*par).wnbc-1 DO IF (*(*tab).wLin)[ix,iy] NE 0 THEN BEGIN IF (*prod).Nd_par GT 0 THEN valdir = WHERE((*(*tab).wVZA)[ix,iy,*] GT 0, Ndir) ELSE Ndir=0 ; Directions valides st='' & FOR ik=0, (*prod).Nu_par-1 DO st=st+line( (*(*tab).wUtab[ik])[ix,iy], (*prod).U_par[ik],/NOUNIT) PRINTF,lun_out,(*(*tab).wLin)[ix,iy],(*(*tab).wCol)[ix,iy],st,Ndir,format='(2I5,A,I4)' IF (*prod).Nd_par GT 0 THEN BEGIN FOR idd = 0, Ndir-1 DO BEGIN id = valdir[idd] st='' & FOR ik=0, (*prod).Nd_par-1 DO st=st+line( (*(*tab).wDtab[ik])[ix,iy,id],(*prod).D_par[ik],/NOUNIT) PRINTF,lun_out,(*(*tab).wSZA)[ix,iy,id]*!RADEG,$ (*(*tab).wVZA)[ix,iy,id]*!RADEG,$ (*(*tab).wAZI)[ix,iy,id]*!RADEG,st,format='(3F7.2,2X,A)' ENDFOR ENDIF ENDIF CLOSE,lun_out END 'HDF_Save' : BEGIN IF FLOAT(!VERSION.RELEASE) LT 5.5 THEN BEGIN info=DIALOG_MESSAGE('Version of IDL greater than 5.4 is needed to use the HDF-EOS capabilities') RETURN ENDIF ; Creation et ouverture en EOS du fichier d'output fileout=DIALOG_PICKFILE(/WRITE,TITLE='Select Filename for HDF-EOS file', FILE='AnaPol_resu.hdf', $ GET_PATH=pathout,PATH=(*par).wpathout) IF STRLEN(fileout) EQ 0 THEN RETURN (*par).wpathout = pathout EOSfileID = EOS_GD_OPEN(fileout,/CREATE) IF EOSfileID EQ -1 THEN BEGIN user_response=DIALOG_MESSAGE('Error opening EOS file.') RETURN ENDIF status=EOS_EH_IDINFO(EOSfileID, HDFfileID, sdID) ; Lien avec un identificateur de fichier HDF ; Definitions des attributs globaux "user-defined" ; HDF_SD_ATTRSET, sdID, 'ATTR_Glob_HDF_SD', 'Ceci est un attribut global HDF_SD user-defined', /STRING ; On recupere les caracteristique de grille et de projection strEOS = define_EOS(pstate) ; Creation de la grille gridID = EOS_GD_CREATE(EOSfileID, strEOS.gridname, $ strEOS.xdim, strEOS.ydim, $ strEOS.uplft, strEOS.lowrgt) ; Affectation des parametres de projection a la grille status = EOS_GD_DEFPROJ(gridID, strEOS.projname, strEOS.zonecode, $ strEOS.spherecode, strEOS.projparam) ; Definition du type de pointage sur les pixels status = EOS_GD_DEFPIXREG(gridID, strEOS.pixcent) ; Definition des dimensions utilisees par EOS_GD_DEFFIELD status = EOS_GD_DEFDIM(gridID, 'XDim', strEOS.xdim) status = EOS_GD_DEFDIM(gridID, 'YDim', strEOS.ydim) status = EOS_GD_DEFDIM(gridID, 'ZDim', strEOS.zdim) ; PRINT, '>>> DEFINED DIMENSIONS : ', strEOS.xdim, strEOS.ydim, strEOS.zdim ;========================================================== ; Definition de la liste de parametres NON DIRECTIONNELS ; Ecriture des ATTRIBUTS locaux predefinis ;========================================================== HDFcode = [99,21,22,24, 5, 6,99,99,99,99,99,99,23,25] FOR ip=0, (*prod).Nu_par-1 DO BEGIN s = size(*(*tab).wUtab[ip]) & ctype = s[s[0]+1] typecode = HDFcode[ctype] ; Format des donnees status = EOS_GD_DEFFIELD(gridID, ((*prod).U_par[ip]).name, "XDim,YDim", typecode) fieldID = HDF_SD_NAMETOINDEX(sdID,((*prod).U_par[ip]).name) ; Index associe au champ EOS sdsID=HDF_SD_SELECT(sdID,fieldID) ; Identificateur de SDS associe a l'index du champ EOS ; Definitions des attribut locaux "user-defined" ; HDF_SD_ATTRSET, sdsID, 'NON-DIR Local Attribute', $ ; 'This field may be used for user defined local attribute', /STRING ; Ecriture des attributs HDF locaux "predefined" cal=DOUBLE(((*prod).U_par[ip]).slope) off=-DOUBLE(((*prod).U_par[ip]).offset)/cal CalData={ Cal: cal, $ ;Calibration Factor Cal_Err: 0.0D, $ ;Calibration Error Offset: off, $ ;Uncalibrated Offset Offset_Err: 0.0D, $ ;Uncalibrated Offset Error Num_Type: 0L } ;Number Type of Uncalibrated Data HDF_SD_SETINFO, sdsID, FILL=((*prod).U_par[ip]).dummy, $ ;FORMAT=, $ ;RANGE=, $ LABEL=((*prod).U_par[ip]).name, $ UNIT=((*prod).U_par[ip]).unit, $ ;COORDSYS=, $ CALDATA=CalData HDF_SD_ENDACCESS, sdsID ; Fermeture de l'acces au SDS ENDFOR ;======================================================= ; Definition de la liste de parametres DIRECTIONNELS ; Ecriture des ATTRIBUTS locaux predefinis ;======================================================= IF (*prod).Nd_par GT 0 THEN BEGIN CalData={ Cal: 0.01d, $ ;Calibration Factor Cal_Err: 0.0D, $ ;Calibration Error Offset: 0.d, $ ;Uncalibrated Offset Offset_Err: 0.0D, $ ;Uncalibrated Offset Error Num_Type: 0L } ;Number Type of Uncalibrated Data status = EOS_GD_DEFFIELD(gridID, 'Sol_Zen_Ang', "XDim,YDim,ZDim", 23) fieldID = HDF_SD_NAMETOINDEX(sdID,'Sol_Zen_Ang') ; Index associe au champ EOS sdsID=HDF_SD_SELECT(sdID,fieldID) ; Identificateur de SDS associe a l'index du champ EOS HDF_SD_SETINFO, sdsID, FILL=0l, LABEL='Sol_Zen_Ang',UNIT='deg.', CALDATA=CalData status = EOS_GD_DEFFIELD(gridID, 'View_Zen_Ang', "XDim,YDim,ZDim", 23) fieldID = HDF_SD_NAMETOINDEX(sdID,'View_Zen_Ang') ; Index associe au champ EOS sdsID=HDF_SD_SELECT(sdID,fieldID) ; Identificateur de SDS associe a l'index du champ EOS HDF_SD_SETINFO, sdsID, FILL=0l, LABEL='View_Zen_Ang',UNIT='deg.', CALDATA=CalData status = EOS_GD_DEFFIELD(gridID, 'Rel_Azim', "XDim,YDim,ZDim", 23) fieldID = HDF_SD_NAMETOINDEX(sdID,'Rel_Azim') ; Index associe au champ EOS sdsID=HDF_SD_SELECT(sdID,fieldID) ; Identificateur de SDS associe a l'index du champ EOS HDF_SD_SETINFO, sdsID, FILL=0l, LABEL='Rel_Azim',UNIT='deg.', CALDATA=CalData ENDIF FOR ip=0, (*prod).Nd_par-1 DO BEGIN s = size(*(*tab).wDtab[ip]) & ctype = s[s[0]+1] typecode = HDFcode[ctype] ; Format des donnees status = EOS_GD_DEFFIELD(gridID, ((*prod).D_par[ip]).name, "XDim,YDim,ZDim", typecode) fieldID = HDF_SD_NAMETOINDEX(sdID,((*prod).D_par[ip]).name) ; Index associe au champ EOS sdsID=HDF_SD_SELECT(sdID,fieldID) ; Identificateur de SDS associe a l'index du champ EOS ; Definitions des attribut locaux "user-defined" ; HDF_SD_ATTRSET, sdsID, 'NON-DIR Local Attribute', $ ; 'This field may be used for user defined local attribute', /STRING ; Ecriture des attributs HDF locaux "predefined" cal=DOUBLE(((*prod).D_par[ip]).slope) off=-DOUBLE(((*prod).D_par[ip]).offset)/cal CalData={ Cal: cal, $ ;Calibration Factor Cal_Err: 0.0D, $ ;Calibration Error Offset: off, $ ;Uncalibrated Offset Offset_Err: 0.0D, $ ;Uncalibrated Offset Error Num_Type: 0L } ;Number Type of Uncalibrated Data HDF_SD_SETINFO, sdsID, FILL=((*prod).D_par[ip]).dummy, $ ;FORMAT=, $ ;RANGE=, $ LABEL=((*prod).D_par[ip]).name, $ UNIT=((*prod).D_par[ip]).unit, $ ;COORDSYS=, $ CALDATA=CalData HDF_SD_ENDACCESS, sdsID ; Fermeture de l'acces au SDS ENDFOR ; Operation de detachement/attachement obligatoires status = EOS_GD_DETACH(gridID) gridID = EOS_GD_ATTACH(EOSfileID, strEOS.gridname) ;====================================== ; Ecriture des parametres NONDIR ;====================================== ; Ecriture des parametres non-directionnels dans le fichier HDF FOR ip=0, (*prod).Nu_par-1 DO BEGIN NonDir=ROTATE(*(*tab).wUtab[ip],7) ; On recupere le tableau des parametres non-directionnels ; On ecrase toutes les valeurs non-physiques par 1 seule valeur nsd=dummy ; afin de pouvoir definir 1 FillValue unique dans le tableau de donnees nsd = WHERE ( NonDir EQ ((*prod).U_par[ip]).satur OR $ NonDir EQ ((*prod).U_par[ip]).unvalid, nb_nsd) IF (nb_nsd GT 0) THEN NonDir(nsd)=((*prod).U_par[ip]).dummy status = EOS_GD_WRITEFIELD(gridID, ((*prod).U_par[ip]).name, NonDir) ENDFOR ;====================================== ; Ecriture des parametres DIR. On commence par les angles ;====================================== IF (*prod).Nd_par GT 0 THEN BEGIN tempo = UINT(*(*Tab).wSZA*!RADEG*100. >0.) FOR i=0,(*par).wseqmax-(*par).wseqmin DO tempo[*,*,i]=ROTATE(tempo[*,*,i],7) ; Rotation status = EOS_GD_WRITEFIELD(gridID, 'Sol_Zen_Ang', tempo) tempo = UINT(*(*Tab).wVZA*!RADEG*100. >0.) FOR i=0,(*par).wseqmax-(*par).wseqmin DO tempo[*,*,i]=ROTATE(tempo[*,*,i],7) ; Rotation status = EOS_GD_WRITEFIELD(gridID, 'View_Zen_Ang', tempo) tempo = UINT(*(*Tab).wAZI*!RADEG*100. >0.) FOR i=0,(*par).wseqmax-(*par).wseqmin DO tempo[*,*,i]=ROTATE(tempo[*,*,i],7) ; Rotation status = EOS_GD_WRITEFIELD(gridID, 'Rel_Azim', tempo) ENDIF FOR ip=0, (*prod).Nd_par-1 DO BEGIN Dir=*(*tab).wDtab[ip] ; On recupere le tableau des parametres directionnels FOR i=0,(*par).wseqmax-(*par).wseqmin DO Dir[*,*,i]=ROTATE(Dir[*,*,i],7) ; Rotation ; On ecrase toutes les valeurs non-physiques par 1 seule valeur nsd=unvalid ; afin de pouvoir definir 1 FillValue unique dans le tableau de donnees nsd = WHERE ( Dir EQ ((*prod).D_par[ip]).satur OR $ Dir EQ ((*prod).D_par[ip]).unvalid, nb_nsd) IF (nb_nsd GT 0) THEN Dir(nsd)=((*prod).D_par[ip]).dummy status = EOS_GD_WRITEFIELD(gridID, ((*prod).D_par[ip]).name, Dir) ENDFOR ;====================================== ; Ecriture des attributs GLOBAUX ;====================================== ; Ecriture d'attributs globaux EOS "user-defined" ; status = EOS_GD_WRITEATTR(gridID, "ATTR_Glob_EOS_GD", 'Attribut global EOS_GD user-defined', HDF_TYPE=4) status = EOS_GD_WRITEATTR(gridID, "SAMPLING", (*par).wsamp, HDF_TYPE=21) status = EOS_GD_DETACH(gridID) ; Fermeture EOS du fichier status = EOS_GD_CLOSE(EOSfileID) END ENDCASE END ; ����� END OF FILEMENU_EVENT ����� ;======================================================================================= ; This function returns the HDF-EOS grid and projection parameters ;--------------------------------------------------------------------------------------- FUNCTION define_EOS,pstate par = (*pstate).wStrParam prod = (*pstate).wStrProd ; Definition des param�eres de grille (sur la zone extraite) gridname='SINUSOIDAL' uplft =DBLARR(2) lowrgt=DBLARR(2) xdim=(*par).wnbc & ydim=(*par).wnbl zdim=LONG((*par).wseqmax-(*par).wseqmin+1) uplft = [ -DOUBLE((*par).wMapSizeWE*500.), DOUBLE((*par).wMapLatC*1.1111E5 + (*par).wMapSizeNS*500.)] lowrgt = [ +DOUBLE((*par).wMapSizeWE*500.), DOUBLE((*par).wMapLatC*1.1111E5 - (*par).wMapSizeNS*500.)] ; Definition des parametres de projection (tout le globe) projname=99l zonecode=0l spherecode=-1l pixcent=0l Sphere = 6371007.1809 ; Radius of reference sphere. If zero, 6370997 meters is used Centmer = (*par).wMapLonC ; Longitude of the central meridian FE = 0 ; False easting in the same units as the semi-major axis FN = 0 ; False northing in the same units as the semi-major axis NZone= 180.*(*prod).resol ; Number of equally spaced latitudinal zones (rows) RFlag = 2 ; Right jsutify columns flag is used to indicate what to do in ; zones with an odd nombers of columns projparam = [ Sphere, $ 0, $ 0, $ 0, $ Centmer, $ 0, $ FE, $ FN, $ NZone, $ 0, $ RFlag, $ 0, $ 0 ] ; Definition des attributs globaux StructHDF={gridname:gridname,xdim:xdim,ydim:ydim,zdim:zdim,uplft:uplft,lowrgt:lowrgt, $ projname:projname,zonecode:zonecode,spherecode:spherecode, $ projparam:projparam,pixcent:pixcent} RETURN, StructHDF END ;========================================================================================= ; ����� ORBITSELECT_EVENT ����� ; S�lection du fichier standard POLDER. ; D�finition du type de produit associ�. G�n�ration de la liste des parametres accessibles ;----------------------------------------------------------------------------------------- PRO OrbitSelect_Event,event FORWARD_FUNCTION define_product,Get_Pos_Orb,path_sep WIDGET_CONTROL,event.top,GET_UVALUE=pstate par = (*pstate).wstrParam WIDGET_CONTROL,event.top,TLB_SET_TITLE='ANAPOL' filein=DIALOG_PICKFILE(FILTER='P*',/MUST_EXIST,TITLE='POLDER File Selection', $ GET_PATH=pathin,path=(*par).wpathin) print,(*par).wpathin print,pathin IF (filein EQ '') THEN RETURN ; seppos = STRPOS(filein,path_sep(),/REVERSE_SEARCH) ; On impose que "filein" corresponde au datafile orbit_label =STRMID(filein,seppos+1,15) STRPUT,filein,'D',seppos+16 fileL = filein & STRPUT,fileL,'L',seppos+16 ; Leader file (*par).wpathin = pathin (*par).wfilein = filein ; Affichage du nom de l'orbite dans la widget OrbitLabel WIDGET_CONTROL,(*(*pstate).wstrWidg).wOrbL,SET_VALUE=orbit_label ; Ouvertude du fichier openr,lun,fileL,/get_Lun,ERROR=err IF err NE 0 THEN BEGIN user_response=DIALOG_MESSAGE('The Leader file corresponding to this product was not found') RETURN ENDIF ; ; Verification rapide que on lit bien un fichier POLDER ; point_lun,lun,8 ref = BYTARR(11) & readu,lun,ref & ref=STRING(ref) IF (ref NE 'PAST33131CN' AND ref NE 'P2ST33131CN' AND ref NE 'SPG9N122-31') THEN BEGIN user_response=DIALOG_MESSAGE('The file was not recognized as a standard POLDER product') RETURN ENDIF ; On ouvre le data file pour recuperer la longueur du record. Seul moyen pour distinguer classe 1/classe 2 !!! openr,lunD,(*par).wfilein,/get_Lun,ERROR=err IF err NE 0 THEN BEGIN user_response=DIALOG_MESSAGE('Error when trying to open file '+(*par).wfilein) RETURN ENDIF ; On lit la taille du record (en interne), pour en deduire la classe point_lun,lunD,58 len_prod = BYTARR(2) & readu,lunD,len_prod length=len_prod[0]*256l+len_prod[1] free_lun,lunD close, lunD ; ; On lit le nom du fichier (en interne), pour en deduire le type point_lun,lun,36 typ_prod = BYTARR(8) & readu,lun,typ_prod typ_prod = STRING(typ_prod) parasol = STRMID(typ_prod,1,1) EQ '3' IF Parasol THEN print,' Parasol data file' ELSE print,'POLDER data file' IF typ_prod EQ 'P3L1TBGC' THEN typ_prod = 'P3L1TBG1' print,' Product type : ',typ_prod IF typ_prod EQ 'P3L1TBG1' AND length NE 738 THEN parasol=2 ; Cas specifique pour les orbites depointees (*par).parasol = parasol *(*pstate).wstrProd = define_product(typ_prod,length,ERROR=err,PARASOL=parasol) IF err NE 0 THEN RETURN ; ; On regarde la liste des produits disponibles. Au passage, on fait une rustine: On multiplie par 2 la pente ; des produits I2 (0 a 65535) afin qu'ils tiennent dans la dynamique des I2 IDL (-32768 a 32767). Cf ce qui est ; fait dans "extract data" ; liste = STRARR(99) & N=0 prod = (*pstate).wstrProd IF (*prod).Nu_par NE 0 THEN liste[N:N-1+(*Prod).Nu_par] = ((*prod).U_par).name N = N + (*prod).Nu_par ; Suite de la liste des parametres : Directionnels IF (*prod).Nd_par NE 0 THEN liste[N:N-1+(*Prod).Nd_par] = ((*prod).D_par).name N = N + (*prod).Nd_par ; Suite de la liste des parametres : Combinaisons non-directionnelles IF (*(*pstate).wstrProd).Nc_par NE 0 THEN liste[N:N-1+(*(*pstate).wstrProd).Nc_par] = ((*prod).C_par).name N = N + (*(*pstate).wstrProd).Nc_par ; Suite de la liste des parametres : Combinaisons directionnelles IF (*(*pstate).wstrProd).Ncd_par NE 0 THEN liste[N:N-1+(*(*pstate).wstrProd).Ncd_par] = ((*prod).Cd_par).name N = N + (*(*pstate).wstrProd).Ncd_par liste = liste[0:N-1] WIDGET_CONTROL,(*(*pstate).wstrWidg).wChanD,SET_VALUE=liste IF (*prod).Nu_par EQ 0 THEN (*par).wchan=100 ELSE (*par).wchan=0 ; ; On s�lectionne le parametre a afficher 'par defaut' ; IF (*(*pstate).wstrProd).Ncd_par NE 0 THEN BEGIN (*par).wchan=300 WIDGET_CONTROL,(*(*pstate).wstrWidg).wChanD,SET_DROPLIST_SELECT=(*prod).Nu_par+(*prod).Nd_par+(*prod).Nc_par GOTO, jumpchan ENDIF IF (*(*pstate).wstrProd).Nc_par NE 0 THEN BEGIN (*par).wchan=200 WIDGET_CONTROL,(*(*pstate).wstrWidg).wChanD,SET_DROPLIST_SELECT=(*prod).Nu_par+(*prod).Nd_par GOTO, jumpchan ENDIF IF (*(*pstate).wstrProd).Nd_par NE 0 THEN BEGIN (*par).wchan=100 WIDGET_CONTROL,(*(*pstate).wstrWidg).wChanD,SET_DROPLIST_SELECT=(*prod).Nu_par GOTO, jumpchan ENDIF (*par).wchan=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wChanD,SET_DROPLIST_SELECT=0 jumpchan : ; ; Determination de la longitude de passage a l'equateur (si niveau 1 ou 2) ; IF STRMID((*prod).type,1,1) EQ 3 THEN LonEq = 0. ELSE BEGIN point_lun,lun,180+360+50 lon = BYTARR(8) & readu,lun,lon READS,STRING(lon),LonEq ENDELSE (*par).wLonEq = lonEq ; On lit maintenant le nombre de pixels par ligne Nlin = 180 * (*prod).resol & Npix=INTARR(Nlin) CASE STRMID(typ_prod,3,1) OF '1' : point_lun,lun,180+360+1620+180+166320l+720+13140+204 '2' : point_lun,lun,180+360+1620+180 +720+13140+204 '3' : point_lun,lun,180+360 +720+13140+204 ENDCASE readf,lun,Npix,format='(3240I4)' PTR_FREE, (*par).pNpix (*par).pNpix = PTR_NEW(Npix) free_lun,lun ; ; Les commandes ci dessous sont equivalents a ce que on fait dans le cas d'un orbitmap (cf AreaSelect_Event) ; On definit la zone de selection par rapport a la zone precedement selectionnee. Par contre, la zone d'affichage ; couvre toute la terre ; latmax=75. (*par).wlatc = (*par).wMapLatc & (*par).wMapLatc = 0. (*par).wlonc = (*par).wMapLonc & (*par).wMapLonc = (*par).wLonEq (*par).wSizeNS = (*par).wMapSizeNS & (*par).wMapSizeNS = 2.*latmax/9.E-3 (*par).wSizeWE = (*par).wMapSizeWE & (*par).wMapSizeWE = (*par).wMapSizeNS * (*par).wdxs / float((*par).wdys) (*par).wMapPos = [0.,0.,(*par).wdxs,(*par).wdys] (*par).wfz = 0 ; Ceci pour indiquer que le browse n'est pas disponible ratio = (*par).wdxs/float((*par).wdys) ; ; Pour le niveau 3, on trace toute la terre: ; IF STRMID((*prod).type,1,1) EQ '3' THEN BEGIN (*par).wMapSizeNS = 2.E4 (*par).wMapSizeWE = 4.E4 (*par).wMapPos = [0.,(*par).wdys/2.-(*par).wdxs/4.,(*par).wdxs,(*par).wdys/2.+(*par).wdxs/4.] latmax = 90. ratio = 2. ENDIF ; ; On fait maintenant les traces ; WSET,(*(*pstate).wstrParam).wid ERASE DEVICE,DECOMPOSE=0 MAP_SET,0.,(*par).wMapLonC,/NOBORDER,/GRID,/LABEL, $ LIMIT=[-latmax,(*par).wLonEq-latmax*ratio,latmax,(*par).wMapLonC+latmax*ratio], $ POSITION=(*par).wMapPos/[(*par).wdxs,(*par).wdys,(*par).wdxs,(*par).wdys],/SINUSOIDAL,COLOR=(*par).wNC+1 MAP_CONTINENTS,/COAST,COLOR=(*par).wNC+1 IF STRMID(typ_prod,3,1) LT 3 THEN BEGIN limites = Get_Pos_Orb(par) OPLOT,limites[2,*],limites[0,*],THICK=2.,COLOR=(*par).wNC+3 OPLOT,limites[1,*],limites[0,*],THICK=2.,COLOR=(*par).wNC+3 ENDIF ; On trace par dessus la zone s�lectionn�e latmax = (*par).wlatc + (*par).wSizeNS/2.*9.E-3 latmin = (*par).wlatc - (*par).wSizeNS/2.*9.E-3 lon1 = (*par).wlonc - (*par).wSizeWE/2.*9.E-3/COS(latmax*!DTOR) lon2 = (*par).wlonc + (*par).wSizeWE/2.*9.E-3/COS(latmax*!DTOR) lon3 = (*par).wlonc + (*par).wSizeWE/2.*9.E-3/COS(latmin*!DTOR) lon4 = (*par).wlonc - (*par).wSizeWE/2.*9.E-3/COS(latmin*!DTOR) OPLOT,[lon1,lon2,lon3,lon4,lon1],[latmax,latmax,latmin,latmin,latmax],THICK=2 ; Il faut rendre un certain nombre de boutons non sensibles WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqS ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqB ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wAutoB ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wMinF ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wMaxF ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wAngleBG,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wMapBG ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wChanD ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wcolBG ,SENSITIVE=0 ; Par contre, les boutons de selection de zone et de Browse deviennent sensible WIDGET_CONTROL,(*(*pstate).wstrWidg).wLonCenF,/SENSITIVE,SET_VALUE=ROUND((*par).wlonc*100.)/100. WIDGET_CONTROL,(*(*pstate).wstrWidg).wLatCenF,/SENSITIVE,SET_VALUE=ROUND((*par).wlatc*100.)/100. WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbLinF ,/SENSITIVE,SET_VALUE=ROUND((*par).wsizeNS) WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbColF ,/SENSITIVE,SET_VALUE=ROUND((*par).wsizeWE) IF STRMID((*prod).type,1,1) EQ '1' THEN $ WIDGET_CONTROL,(*(*pstate).wstrWidg).wBrowseB,/SENSITIVE ; Pas de browse pour les produits autres que niveau-1 WIDGET_CONTROL,(*(*pstate).wstrWidg).wZoomB ,/SENSITIVE,EVENT_PRO='AreaSelect_Event' WIDGET_CONTROL,(*(*pstate).wstrWidg).wOrbMapB,/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wReadDataB,/SENSITIVE ; On sp�cifie que les op�rations sur la fen�tre ont pour parent OrbitMap_Event WIDGET_CONTROL,(*(*pstate).wstrWidg).wDraw,EVENT_PRO='AreaSelect_Event',/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wReadDataB,/SENSITIVE END ;����� END OF ORBITSELECT_EVENT ����� ;========================================================================================= ; ����� AREASELECT_EVENT ����� ; Selection de la zone d'�tude. ; Cette s�lection se fait soit au clavier, soit avec la souris ; On peut aussi faire un browse, et un zoom sur une zone pre-selectionnee ;----------------------------------------------------------------------------------------- PRO AreaSelect_Event,event FORWARD_FUNCTION Get_Pos_Orb,make_browse WIDGET_CONTROL,event.id,GET_UVALUE=uval WIDGET_CONTROL,event.top,GET_UVALUE=pstate WIDGET_CONTROL,event.top,TLB_SET_TITLE='AREA SELECTION' par = (*pstate).wstrParam prod = (*pstate).wstrProd WSET,(*par).wid ; ; La zone est red�finie par une action directement sur les coordonn�es ; IF (uval EQ 'sizeWE' OR uval EQ 'sizeNS' OR uval EQ 'loncent' OR uval EQ 'latcent') THEN BEGIN WIDGET_CONTROL,event.id,GET_VALUE=val CASE uval OF 'sizeWE' : (*par).wsizeWE = val 'sizeNS' : (*par).wsizeNS = val 'loncent' : (*par).wlonc = val 'latcent' : (*par).wlatc = val ENDCASE IF uval EQ 'loncent' AND (*par).wfz EQ 0 THEN (*par).wMapLonC = (*par).wlonc ; Il faut calculer wZPos . C'est fait plus bas (en meme temps que "orbitMap") ENDIF ; ; La zone peut aussi etre definie a partir de la fenetre, auquel cas on obtient wZpos ; IF uval EQ 'draw' THEN BEGIN ; Ici, on est dans le cas bouton presse. On garde la valeur en memoire IF event.press THEN BEGIN (*par).wZpos[0] = event.x (*par).wZpos[1] = event.y ; On rep�re le "clic" par une croix PLOT,[event.x],[event.y],xrange=[0.,(*par).wdxs-1],yrange=[0.,(*par).wdxs-1],$ PSYM=7,COLOR=(*par).wNC+2,/NOERASE,xstyle=5,ystyle=5,/NORMAL,POS=[0.,0.,1.,1.] RETURN ; Rien d'autre a faire pour un click down ENDIF ; Ici, on relache la souris. On garde la valeur, et on regarde si elle a boug� IF event.release THEN BEGIN (*par).wZpos[2] = event.x (*par).wZpos[3] = event.y IF ((*par).wZpos[0] EQ (*par).wZpos[2]) AND $ ((*par).wZpos[1] EQ (*par).wZpos[3]) THEN BEGIN ; Si la souris n'a pas bouge, on fait un reset de la zone de selection a celle du trace, et on rend le bouton zoom non sensible (*par).wlatc = (*par).wMapLatc (*par).wlonc = (*par).wMapLonc (*par).wSizeNS = (*par).wMapSizeNS (*par).wSizeWE = (*par).wMapSizeWE (*par).wZpos = (*par).wMapPos WIDGET_CONTROL,(*(*pstate).wstrWidg).wZoomB,SENSITIVE=0 ENDIF ELSE WIDGET_CONTROL,(*(*pstate).wstrWidg).wZoomB,/SENSITIVE ; ; On a donc d�finit une nouvelle zone, dont on peut calculer la position en coordonn�es geographiques ; fac = (*par).wMapSizeNS * 9.E-3 / ((*par).wMapPos[3]-(*par).wMapPos[1]) ; degr�s par pixel (*par).wlatc = (*par).wMapLatC + ((*par).wZpos[3]+(*par).wZpos[1]-(*par).wdys)/2. * fac (*par).wlonc = (*par).wMapLonC + ((*par).wZpos[2]+(*par).wZpos[0]-(*par).wdxs)/2. * fac/COS((*par).wlatc*!DTOR) (*par).wsizeNS = (*par).wMapSizeNS * ABS((*par).wZpos[3]-(*par).wZpos[1]) / ((*par).wMapPos[3]-(*par).wMapPos[1]) (*par).wsizeWE = (*par).wMapSizeWE * ABS((*par).wZpos[2]-(*par).wZpos[0]) / ((*par).wMapPos[2]-(*par).wMapPos[0]) IF (*par).wfz EQ 0 THEN (*par).wMapLonC = (*par).wlonc ENDIF ENDIF ; ; Action sur le bouton 'OrbitMap'. La zone precedement affichee devient la zone selectionnee. On affiche l'ensemble ; de l'orbite IF uval EQ 'orbitmap' THEN BEGIN (*par).wlatc = (*par).wMapLatc & (*par).wMapLatc = 0. (*par).wlonc = (*par).wMapLonc & (*par).wMapLonc = (*par).wLonEq (*par).wSizeNS = (*par).wMapSizeNS & (*par).wMapSizeNS = 150./9.E-3 (*par).wSizeWE = (*par).wMapSizeWE & (*par).wMapSizeWE = (*par).wMapSizeNS * (*par).wdxs / float((*par).wdys) (*par).wMapPos = [0.,0.,(*par).wdxs,(*par).wdys] (*par).wfz = 0 ; Ceci pour indiquer que le browse n'est pas disponible ; Pour le niveau 3, on trace toute la terre: IF STRMID((*prod).type,1,1) EQ '3' THEN BEGIN (*par).wMapSizeNS = 2.E4 (*par).wMapSizeWE = 4.E4 (*par).wMapPos = [0.,(*par).wdys/2.-(*par).wdxs/4.,(*par).wdxs,(*par).wdys/2.+(*par).wdxs/4.] ENDIF ENDIF ; ; Si on fait un zoom, on red�finit la zone de trac� par rapport a la zone s�lectionn�e ; IF uval EQ 'zoom' OR uval EQ 'browse' THEN BEGIN (*par).wMapLatC = (*par).wlatc (*par).wMapLonC = (((*par).wlonc+180.) MOD 360.) -180. (*par).wMapSizeNS = (*par).wSizeNS (*par).wMapSizeWE = (*par).wSizeWE ; Deux cas suivant que on est plutot en horizontal ou en vertical Ratio = float((*par).wsizeWE)/float((*par).wsizeNS)/float((*par).wdxs)*float((*par).wdys) IF (Ratio LT 1.) THEN (*par).wMapPos = [0.5-Ratio/2.,0.,0.5+Ratio/2.,1.] $ ; Plus grande dimension suivant Y ELSE (*par).wMapPos = [0.,0.5-1./Ratio/2.,1., 0.5+1./Ratio/2.] (*par).wMapPos = (*par).wMapPos * [(*par).wdxs,(*par).wdys,(*par).wdxs,(*par).wdys] (*par).wfz = 0 ; Ceci pour indiquer que le browse n'est pas disponible (*par).wZPos = (*par).wMapPos ; La zone de s�lection est la meme que la zone de visualisation ENDIF ; ; Si on a demand� un browse, on le calcule. ; IF uval EQ 'browse' THEN BEGIN PTR_FREE,(*par).ptrbrowse ; On commence par liberer le pointeur sur le browse precedent latmin = (*par).wMapLatC - (*par).wMapSizeNS/2.*9.E-3 latmax = (*par).wMapLatC + (*par).wMapSizeNS/2.*9.E-3 PTR_FREE,(*par).ptrbrowse (*par).ptrbrowse = make_browse((*par).wfilein,latmin,latmax,(*par).wMapLonc,$ float((*par).wsizeWE)/float((*par).wsizeNS), 200,PARASOL=(*par).parasol) s = SIZE((*(*par).ptrbrowse).tab) (*par).wfz = MIN( [ (*par).wdxs/s[1],(*par).wdys/s[2] ] ) (*par).wMapPos = [((*par).wdxs - s[1]*(*par).wfz)/2., ((*par).wdys - s[2]*(*par).wfz)/2., $ ((*par).wdxs + s[1]*(*par).wfz)/2., ((*par).wdys + s[2]*(*par).wfz)/2.] (*par).wZPos = (*par).wMapPos ; La zone de s�lection est la meme que la zone de visualisation ENDIF ; ; On fait maintenant les trac�s ; DEVICE, DECOMPOSE=0 ERASE,COLOR=(*par).wNC+4 IF (*par).wfz NE 0 THEN BEGIN ; Si un browse est disponible, on le trace struc = (*par).ptrbrowse s = SIZE((*struc).tab) IF s[0] EQ 3 THEN BEGIN ; On peut avoir des browse "3 couleurs" ou "monochrome" DEVICE,/DECOMPOSE TV,REBIN( (*struc).tab,s[1]*(*par).wfz,s[2]*(*par).wfz,3,/SAMPLE),(*par).wMapPos[0],(*par).wMapPos[1],TRUE=3 ENDIF ELSE BEGIN DEVICE,DECOMPOSE=0 TV,REBIN( (*struc).tab,s[1]*(*par).wfz,s[2]*(*par).wfz,/SAMPLE),(*par).wMapPos[0],(*par).wMapPos[1] ENDELSE ENDIF ; ; On va maintenant tracer la carte. Puisque on veut la tracer sur toute la fenetre, il faut ; recalculer les positions des extremes: ; latmax = (*par).wMapLatC + 0.5 * (*par).wMapSizeNS*9.E-3 / ((*par).wMapPos[3]-(*par).wMapPos[1]) * (*par).wdys latmin = (*par).wMapLatC - 0.5 * (*par).wMapSizeNS*9.E-3 / ((*par).wMapPos[3]-(*par).wMapPos[1]) * (*par).wdys delta_lat = latmax-latmin IF latmax*latmin LE 0. THEN MinAbsLon = 0. ELSE $ MinAbsLon = MIN(ABS([latmin,latmax])) delta_lon = delta_lat * (*par).wdxs/float((*par).wdys) /COS(MinAbsLon*!DTOR) ; ; On traite les cas tordus ou lat depassent les poles pos = [0.,0.,1.,1.] IF latmax GT 90. THEN BEGIN pos[3] = 0.5 + ( 90.-(*par).wMapLatC)/(latmax-(*par).wMapLatC)/2. latmax = 90. ENDIF IF latmin LT -90. THEN BEGIN pos[1] = 0.5 - (-90.-(*par).wMapLatC)/(latmin-(*par).wMapLatC)/2. latmin = -90. ENDIF ; ; On peut alors tracer la carte (*par).wMapLonC = (((*par).wMapLonC+180.) MOD 360.) - 180. MAP_SET,0.,(*par).wMapLonC,/NOBORDER,/GRID,/LABEL, $ LIMIT=[latmin,(*par).wMapLonC-delta_lon/2.,latmax,(*par).wMapLonC+delta_lon/2.], $ POSITION=pos,/SINUSOIDAL,/NOERASE,COLOR=(*par).wNC+1 MAP_CONTINENTS,/COAST,COLOR=(*par).wNC+1,HIRES=(delta_lat LT 15.) ; Si le browse n'est pas disponible, on indique les limites de l'orbite IF (*par).wfz EQ 0 AND STRMID((*prod).type,1,1) NE '3' THEN BEGIN limites = Get_Pos_Orb(par) OPLOT,limites[2,*],limites[0,*],THICK=2.,COLOR=(*par).wNC+3 OPLOT,limites[1,*],limites[0,*],THICK=2.,COLOR=(*par).wNC+3 ENDIF ; ; On trace par dessus la zone s�lectionn�e ; IF (*par).wfz EQ 0 THEN BEGIN ; Cas ou il n'y a pas de browse (la projection suit la zone de selection) tailleX = (latmax-latmin)*(pos[2]-pos[0])/(pos[3]-pos[1])/9.E-3 dlat = (*par).wSizeNS/2.*9.E-3 PLOT,[-tailleX,tailleX],[latmin,latmax],XRANGE=[-tailleX,tailleX],YRANGE=[latmin,latmax], $ POS=pos,XSTYLE=5,YSTYLE=5,/NOERASE,/NODATA OPLOT,[-(*par).wSizeWE ,(*par).wSizeWE ,(*par).wSizeWE ,-(*par).wSizeWE ,-(*par).wSizeWE ], $ [(*par).wlatc+dlat,(*par).wlatc+dlat,(*par).wlatc-dlat, (*par).wlatc-dlat, (*par).wlatc+dlat],THICK=2 ENDIF ELSE BEGIN ; Si on a un Browse, c'est plus facile: P = (*par).wZpos PLOT,[P[0],P[2],P[2],P[0],P[0]],[P[3],P[3],P[1],P[1],P[3]],xrange=[0.,(*par).wdxs-1],yrange=[0.,(*par).wdxs-1],$ /NOERASE,xstyle=5,ystyle=5,/NORMAL,POS=[0.,0.,1.,1.],THICK=2 ENDELSE ; ; On sp�cifie les nouvelles valeurs de la zone s�lectionn�e les boites qui vont bien WIDGET_CONTROL,(*(*pstate).wstrWidg).wLonCenF,SET_VALUE=ROUND((*par).wlonc*100.)/100. WIDGET_CONTROL,(*(*pstate).wstrWidg).wLatCenF,SET_VALUE=ROUND((*par).wlatc*100.)/100. WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbLinF ,SET_VALUE=ROUND((*par).wsizeNS) WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbColF ,SET_VALUE=ROUND((*par).wsizeWE) ; IF uval EQ 'orbitmap' THEN BEGIN ; Si on est dans 'orbitmap', on vient peut etre de la visu. Il faut rendre un certain nombre de boutons non sensibles WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqS ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqB ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wAutoB ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wMinF ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wMaxF ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wAngleBG,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wMapBG ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wChanD ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wcolBG ,SENSITIVE=0 ; Par contre, les boutons de selection de zone et de Browse deviennent sensible WIDGET_CONTROL,(*(*pstate).wstrWidg).wLonCenF,/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wLatCenF,/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbLinF ,/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbColF ,/SENSITIVE IF STRMID((*prod).type,1,1) EQ '1' THEN $ WIDGET_CONTROL,(*(*pstate).wstrWidg).wBrowseB,/SENSITIVE ; Pas de browse pour les produits autres que niveau-1 ; On sp�cifie que les op�rations sur la fen�tre ont pour parent OrbitMap_Event WIDGET_CONTROL,(*(*pstate).wstrWidg).wDraw ,EVENT_PRO='AreaSelect_Event' WIDGET_CONTROL,(*(*pstate).wstrWidg).wReadDataB,/SENSITIVE ; Le bouton zoom est maintenant g�r� par AreaSelect_Event WIDGET_CONTROL,(*(*pstate).wstrWidg).wZoomB,/SENSITIVE,EVENT_PRO='AreaSelect_Event' ENDIF ; END ; ����� END OF AREA_SELECT ����� ;========================================================================================= ; ����� READDATA_EVENT ����� ; Lecture des donn�es, et affichage du premier parametre ; Cette routine fait appel a : ; Get_Pixels : Lecture des pixels POLDER (sur la zone choisie, eventuellement echantillon�) ; Extract_Data : A partir des pixels POLDER, creation des tableaux pour les param�tres selectionn�s ; Make_visu : G�n�re le tableau de visualisation (en utilisant les min/max) ; display : Affichage de la visualisation ;----------------------------------------------------------------------------------------- PRO ReadData_Event,event FORWARD_FUNCTION Get_Pixels WIDGET_CONTROL,event.top,GET_UVALUE=pstate WIDGET_CONTROL,event.id,GET_UVALUE=uval par = (*pstate).wstrParam ; Lecture des donnees POLDER. On prend une taille maximale suivant que on regarde un produit directionnel ou non IF (*(*pstate).wstrProd).Nd_par EQ 0 THEN dimMax=450 ELSE dimMax=150 PtPix=Get_Pixels(pstate,dimMax) ; Ici, dimMax est la dimension maximale du tableau de sortie (ligne ou colonne) ; ; Extraction des donnees utiles Extract_Data,ptPix,pstate ; Si la zone est mal choisie... IF (*par).wseqmax EQ -99 THEN BEGIN user_response=DIALOG_MESSAGE('SORRY, No data in selected area') RETURN ENDIF IF (*par).wfz EQ 1 THEN WIDGET_CONTROL,event.top,TLB_SET_TITLE='DATA ANALYSIS - FULL RESOLUTION' $ ELSE WIDGET_CONTROL,event.top,TLB_SET_TITLE='DATA ANALYSIS - SAMPLED 1/'+STRING((*par).wfz,format='(I2)') ; Genere un tableau directement visualisable en fonction des differents choix Make_Visu,pstate ; On Etend les dimensions de la zone de trace ; Facteur d'�chelle: On recopie un pixel sur wfz pixels ecran (*par).wMapLatc = (*par).wLatc (*par).wMapLonc = (((*par).wlonc+180.) MOD 360.) -180. (*par).wMapsizeNS = (*par).wsizeNS (*par).wMapsizeWE = (*par).wsizeWE (*par).wfz = MIN( [ (*par).wdxs/(*par).wnbc,(*par).wdys/(*par).wnbl ] ) (*par).wMapPos = [((*par).wdxs - (*par).wnbc*(*par).wfz)/2., ((*par).wdys - (*par).wnbl*(*par).wfz)/2., $ ((*par).wdxs + (*par).wnbc*(*par).wfz)/2., ((*par).wdys + (*par).wnbl*(*par).wfz)/2.] (*par).wZPos = (*par).wMapPos ; La zone de s�lection est la meme que la zone de visualisation ; On visualise le tableau pour la 1�re fois (configuration initiale de no seq, etc...) display,pstate display_ctbl,pstate ; On fait glisser le slider sur la valeur de la sequence courante (utile dans le mode "loop") WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqS,SET_VALUE=(*par).wseq ; Apres la lecture, et tant que les parametres n'ont pas change, le bouton ; pour la lecture devient non sensible WIDGET_CONTROL,(*(*pstate).wstrWidg).wReadDataB,SENSITIVE=0 ; On rend actifs tous les boutons de controle du trace WIDGET_CONTROL,(*(*pstate).wstrWidg).wMapBG ,/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wChanD ,/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wAutoB ,/SENSITIVE ; ; Le bouton de controle de la palette de couleur si on regarde un parametre "simple" ; IF (*par).wchan/100 LE 1 THEN $ WIDGET_CONTROL,(*(*pstate).wstrWidg).wcolBG ,/SENSITIVE ; ; Ci dessous, les boutons directionnels ne sont activ�s que si on visualise ; un param�tre directionnel IF (*par).wchan/100 EQ 1 OR (*par).wchan/100 EQ 3 THEN BEGIN WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqS ,/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqB ,/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wAngleBG,/SENSITIVE ENDIF ; Les boutons vmin/vmax sont activ�s si on est en position "user defined" IF ( (*par).wauto EQ 0b) THEN BEGIN WIDGET_CONTROL,(*(*pstate).wstrWidg).wMinF,/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wMaxF,/SENSITIVE ENDIF ; Les boutons de selection de zone deviennent non sensible WIDGET_CONTROL,(*(*pstate).wstrWidg).wLonCenF,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wLatCenF,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbLinF ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbColF ,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wBrowseB,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wzoomB,SENSITIVE=0,EVENT_PRO='ReadData_Event' ; On sp�cifie que les op�rations sur la fen�tre sont maintenant trait�s par Fenetre_Event WIDGET_CONTROL,(*(*pstate).wstrWidg).wDraw,EVENT_PRO='Fenetre_Event' END ; ����� END OF READDATA_EVENT ����� ;========================================================================================= ; ����� VISU_EVENT ����� ; Gestion des actions qui modifient le tableau de visualisation. Choix du canal, min et max ; de la palette de couleur. Ajout des angles ou de la carte sur le trac�. ;----------------------------------------------------------------------------------------- PRO Visu_Event,event WIDGET_CONTROL,event.top,GET_UVALUE=pstate WIDGET_CONTROL,event.id,GET_UVALUE=uval IF (uval NE 'channel') THEN WIDGET_CONTROL,event.id,GET_VALUE=val par = (*pstate).wstrParam prod = *(*pstate).wstrProd ; ; On ferme les fenetres 4, 5 et 6 ; DEVICE, WINDOW_STATE=winstate FOR w=4,6 DO IF winstate[w] THEN WDELETE,w ; Si il y a une fenetre de display de valeur, on la vire IF (*par).wvdisp GT 0 THEN BEGIN IF WIDGET_INFO((*par).wvdisp,/VALID_ID) THEN WIDGET_CONTROL,(*par).wvdisp,/DESTROY (*par).wvdisp=0 ENDIF CASE uval OF 'channel': BEGIN chan_old = (*par).wchan chabeg = [0,prod.Nu_par,prod.Nu_par+prod.Nd_par,prod.Nu_par+prod.Nd_par+prod.Nc_par] chaend = [prod.Nu_par,prod.Nu_par+prod.Nd_par,prod.Nu_par+prod.Nd_par+prod.Nc_par, $ prod.Nu_par+prod.Nd_par+prod.Nc_par+prod.Ncd_par] v = WHERE( event.index GE chabeg AND event.index LT chaend) & v=v[0] (*par).wchan = 100*v + event.index-chabeg[v] ; Si la selection min/max etait en manuelle, et que l'unite a chang�, alors on va passer en automatique ; L'objectif est de pouvoir garder une selection manuelle, si on n'a pas chang� d'unit� IF (*par).wauto EQ 0 THEN BEGIN ip_old = chan_old MOD 100 ip_new = (*par).wchan MOD 100 CASE (chan_old/100) OF 0 : unit_old = prod.U_par[ip_old].unit 1 : unit_old = prod.D_par[ip_old].unit 2 : unit_old = prod.U_par[(prod.C_par[ip_old]).p0].unit 3 : unit_old = prod.D_par[(prod.Cd_par[ip_old]).p0].unit ENDCASE CASE v OF 0 : unit_new = prod.U_par[ip_new].unit 1 : unit_new = prod.D_par[ip_new].unit 2 : unit_new = prod.U_par[(prod.C_par[ip_new]).p0].unit 3 : unit_new = prod.D_par[(prod.Cd_par[ip_new]).p0].unit ENDCASE IF unit_old NE unit_new THEN BEGIN WIDGET_CONTROL,(*(*pstate).wstrWidg).wAutoB,SET_VALUE='AUTO' WIDGET_CONTROL,(*(*pstate).wstrWidg).wMinF,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wMaxF,SENSITIVE=0 (*par).wauto = 1b ENDIF ENDIF ; Si on est en parametre directionnel ou non directionnel, il faut activer/desactiver slider ; et groupe des angles IF (v EQ 1 OR v EQ 3) THEN BEGIN WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqS ,/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqB ,/SENSITIVE WIDGET_CONTROL,(*(*pstate).wstrWidg).wAngleBG,/SENSITIVE ENDIF ELSE BEGIN WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqS , SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqB , SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wAngleBG, SENSITIVE=0 ENDELSE IF (v EQ 2 OR v EQ 3) THEN BEGIN ; On est dans le cas de composition de parametres ; on force la palette a Noir et blanc WIDGET_CONTROL, (*(*pstate).wstrWidg).wcolBG,GET_VALUE=c IF c NE 0 THEN BEGIN make_palette,(*par).wNc,0 WIDGET_CONTROL, (*(*pstate).wstrWidg).wcolBG,SET_VALUE=0 ENDIF WIDGET_CONTROL, (*(*pstate).wstrWidg).wcolBG,SENSITIVE=0 ENDIF ELSE WIDGET_CONTROL, (*(*pstate).wstrWidg).wcolBG,/SENSITIVE END 'angles' : BEGIN IF val[2] AND val[3] AND (*par).wactang[2] THEN val[2]=0b ; Les boutons 2 et 3 IF val[2] AND val[3] AND (*par).wactang[3] THEN val[3]=0b ; sont exclusifs (*par).wactang=val WIDGET_CONTROL,event.id,SET_VALUE=val END 'map' : BEGIN IF val[1] EQ 1b AND val[0] EQ 0b AND (*par).wactMap[0] EQ 0b THEN val[0]=1b IF val[0] EQ 0b THEN val[1]=0b ; On ne clique pas High Res si Map n'est pas clique (*par).wactMap=val WIDGET_CONTROL,event.id,SET_VALUE=val END 'sequence': (*par).wseq=val 'loop' : 'min' : (*par).wvmin=val 'max' : (*par).wvmax=val 'ctbl' : make_palette,(*par).wNC,val ; ; Toggle entre table de couleur automatique/manuel. On active/desactive les ; widgets qui permettent de choisir vmin/vmax 'auto' : BEGIN (*par).wauto = val IF ( (*par).wauto EQ 0b) THEN BEGIN WIDGET_CONTROL,(*(*pstate).wstrWidg).wMinF,SENSITIVE=1 WIDGET_CONTROL,(*(*pstate).wstrWidg).wMaxF,SENSITIVE=1 ENDIF ELSE BEGIN WIDGET_CONTROL,(*(*pstate).wstrWidg).wMinF,SENSITIVE=0 WIDGET_CONTROL,(*(*pstate).wstrWidg).wMaxF,SENSITIVE=0 ENDELSE END ENDCASE ; Si on a modifie le range des min/max, ou le choix du canal, il faut recalculer vvisu ; Sinon, on le garde IF (uval EQ 'channel' OR uval EQ 'min' OR uval EQ 'max' OR $ (uval EQ 'auto' AND (*par).wauto EQ 1b)) THEN Make_Visu,pstate IF (uval EQ 'loop') THEN BEGIN vseqmin = (*par).wseqmin vseqmax = (*par).wseqmax ENDIF ELSE BEGIN vseqmin = (*par).wseq vseqmax = vseqmin ENDELSE ; Si on a modifie la palette de couleur ou les Min Max, alors on trace la palette IF (uval EQ 'channel' OR uval EQ 'min' OR uval EQ 'max' OR $ uval EQ 'ctbl' OR (uval EQ 'auto' AND (*par).wauto EQ 1b)) THEN display_ctbl,pstate ; ; Boucle sur les sequences, et trac� FOR iseq = vseqmin, vseqmax DO BEGIN WIDGET_CONTROL,(*(*pstate).wstrWidg).wSeqS,SET_VALUE=iseq (*par).wseq = iseq display,pstate WAIT,0.5 ENDFOR END ; ����� END OF VISU_EVENT ����� ;========================================================================================= ; ����� FENETRE_EVENT ����� ; Gestion des actions sur la fenetre de trac� lorsque onest en visusalisation de donn�es. ; On rep�re la zone s�lectionn�e. On ouvre des fenetres diff�rentes, suivant le contexte, pour analyse ;----------------------------------------------------------------------------------------- PRO Fenetre_Event,event COMMON COM_L2TOGV,P COMMON COM_L2TLGV,Q FORWARD_FUNCTION line,bin WIDGET_CONTROL,event.top,GET_UVALUE=pstate WIDGET_CONTROL,event.id,GET_VALUE=wid,GET_UVALUE=uval DEVICE,DECOMPOSE=0 par = (*pstate).wstrParam prod = *(*pstate).wstrProd struc = *(*pstate).wstrTab ; Si il y a une fenetre de display de valeur, on la vire IF (*par).wvdisp GT 0 THEN BEGIN IF WIDGET_INFO((*par).wvdisp,/VALID_ID) THEN WIDGET_CONTROL,(*par).wvdisp,/DESTROY (*par).wvdisp=0 ENDIF ; ; Les lignes ci dessous sont pour contourner un bug d'IDL: On a des problemes lorsque l'option Hi-RES est ; affichee. Donc on la desactive ; IF (*par).wactMap[1] EQ 1b THEN BEGIN (*par).wactMap[1] = 0b WIDGET_CONTROL,(*(*pstate).wstrWidg).wMapBG,SET_VALUE=(*par).wactMap ENDIF ; Lorsqu'un "press" est effectu� sur la fen�tre de trac�, on r�cup�re la position du curseur IF event.press THEN BEGIN (*par).wZpos[0] = event.x (*par).wZpos[1] = event.y ; On rep�re le "clic" par une croix WSET,(*par).wid display,pstate PLOT,[event.x],[event.y],xrange=[0.,(*par).wdxs-1],yrange=[0.,(*par).wdxs-1],$ PSYM=7,COLOR=(*par).wNC+2,/NOERASE,xstyle=5,ystyle=5,/NORMAL,POS=[0.,0.,1.,1.] ENDIF ; Lorsque un "release" est effectu� sur la fen�tre de trac� IF event.release THEN BEGIN (*par).wZpos[2] = event.x (*par).wZpos[3] = event.y ; ; On calcule la zone s�lectionn�e, et on entre les valeurs dans les boites correspondantes ; fac = (*par).wMapSizeNS * 9.E-3 / ((*par).wMapPos[3]-(*par).wMapPos[1]) ; degr�s par pixel (*par).wlatc = (*par).wMapLatC + ((*par).wZpos[3]+(*par).wZpos[1]-(*par).wdys)/2. * fac (*par).wlonc = (*par).wMapLonC + ((*par).wZpos[2]+(*par).wZpos[0]-(*par).wdxs)/2. * fac/COS((*par).wlatc*!DTOR) (*par).wsizeNS = (*par).wMapSizeNS * ABS((*par).wZpos[3]-(*par).wZpos[1]) / ((*par).wMapPos[3]-(*par).wMapPos[1]) (*par).wsizeWE = (*par).wMapSizeWE * ABS((*par).wZpos[2]-(*par).wZpos[0]) / ((*par).wMapPos[2]-(*par).wMapPos[0]) WIDGET_CONTROL,(*(*pstate).wstrWidg).wLonCenF,SET_VALUE=ROUND((*par).wlonc*100.)/100. WIDGET_CONTROL,(*(*pstate).wstrWidg).wLatCenF,SET_VALUE=ROUND((*par).wlatc*100.)/100. WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbLinF ,SET_VALUE=ROUND((*par).wsizeNS) WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbColF ,SET_VALUE=ROUND((*par).wsizeWE) ;==================================================================================================== ; Ci dessous les actions dans le cas ou la souris n'a pas �t� d�plac�e entre clicks down et up ;==================================================================================================== IF (*par).wZpos[0] EQ (*par).wZpos[2] AND (*par).wZpos[1] EQ (*par).wZpos[3] THEN BEGIN ; ; Calcul de la position en coordonn�es pixel POLDER ix = (event.x - (*par).wMapPos[0])/(*par).wfz iy = (event.y - (*par).wMapPos[1])/(*par).wfz iseq = (*par).wseq-(*par).wseqmin ; ; Si on est en dehors de la zone de trace, on ne fait pas de plot ; IF ix LT 0 OR ix GE (*par).wnbc OR iy LT 0 OR iy GE (*par).wnbl THEN GOTO, jump_traces ; ; On indique la valeur physique des differents parametres selectionnes dans une widget texte texte = STRARR(100) texte[0] = '======== POSITION ========' & N=1 texte[N] = ' Latitude :'+STRING((*par).wlatc,format='(F6.1," deg.")') & N=N+1 texte[N] = ' Longitude :'+STRING((*par).wlonc,format='(F6.1," deg.")') & N=N+1 texte[N] = ' line/col :'+STRING((*struc.wLin)[ix,iy],(*struc.wCol)[ix,iy],$ format='(" [",i4,",",i4,"] ")') & N=N+1 texte[N] = ' ' & N=N+1 texte[N] = '= NON-DIRECTIONAL PARAMETERS =' & N=N+1 FOR i=0,prod.Nu_par-1 DO BEGIN texte[N] = line( (*struc.wUtab[i])[ix,iy],prod.U_par[i]) N=N+1 ENDFOR IF prod.Nd_par GT 0 THEN BEGIN texte[N] = ' ' & N=N+1 texte[N] = '=== DIRECTIONAL PARAMETERS ===' & N=N+1 IF (*struc.wSZA)[ix,iy,iseq] EQ -99. THEN GOTO, jumpang texte[N] = 'Solar Zen. Ang.:'+STRING((*struc.wSZA)[ix,iy,iseq]*!RADEG,format='(F6.1," deg.")') & N=N+1 texte[N] = 'View Zen. Ang.:'+STRING((*struc.wVZA)[ix,iy,iseq]*!RADEG,format='(F6.1," deg.")') & N=N+1 texte[N] = 'Relative. Azim.:'+STRING((*struc.wAZI)[ix,iy,iseq]*!RADEG,format='(F6.1," deg.")') & N=N+1 IF (*par).wActAng[2] THEN BEGIN pha = ACOS(COS((*struc.wSZA)[ix,iy,iseq])*COS((*struc.wVZA)[ix,iy,iseq]) + $ SIN((*struc.wSZA)[ix,iy,iseq])*SIN((*struc.wVZA)[ix,iy,iseq])* $ COS((*struc.wAZI)[ix,iy,iseq])) texte[N] = 'Phase Angle :'+STRING(pha*!RADEG,format='(F6.1," deg.")') & N=N+1 ENDIF IF (*par).wActAng[3] THEN BEGIN gli = ACOS(COS((*struc.wSZA)[ix,iy,iseq])*COS((*struc.wVZA)[ix,iy,iseq]) - $ SIN((*struc.wSZA)[ix,iy,iseq])*SIN((*struc.wVZA)[ix,iy,iseq])* $ COS((*struc.wAZI)[ix,iy,iseq])) texte[N] = 'Off-glint Angle:'+STRING(gli*!RADEG,format='(F6.1," deg.")') & N=N+1 ENDIF jumpang: FOR i=0,prod.Nd_par-1 DO BEGIN texte[N] = line( (*struc.wDtab[i])[ix,iy,iseq],prod.D_par[i]) N=N+1 ENDFOR ENDIF IF prod.type EQ 'L1TBG1' THEN BEGIN texte[N] = ' ' & N=N+1 texte[N] = '=== DQX ===' & N=N+1 DQX = REFORM((*struc.wDQX)[ix,iy,*]) FOR i=0, N_ELEMENTS(DQX)-1 DO TEXTE(N+i)=STRING(i+1,bin(DQX[i]),FORMAT='("Dir",I3,x,A)') N = N + N_ELEMENTS(DQX) ENDIF texte = texte[0:N-1] base = WIDGET_BASE(TITLE='Data Values') cm = WIDGET_TEXT(base,value=texte,xsize=30,ysize=N,/WRAP) WIDGET_CONTROL, Base,/REALIZE,TLB_SET_Xoffset=(*par).tlb_size[0]+(*par).inter,TLB_SET_Yoffset=200+2*(*par).inter (*par).wvdisp = base ; ; Trace des positions angulaires ; IF prod.Nd_par GT 0 THEN BEGIN window,5,xsize=200,ysize=200,TITLE='Angular Positions',XPOS=(*par).tlb_size[0]+(*par).inter,YPOS=(*par).inter plot_BRDF, *par, $ (*(*(*pstate).wstrTab).wSZA )[ix,iy,*] * !RADEG, $ (*(*(*pstate).wstrTab).wVZA )[ix,iy,*] * !RADEG, $ (*(*(*pstate).wstrTab).wAZI )[ix,iy,*] * !RADEG ENDIF ; ; Si on regarde un parametre directionnel, on trace sa valeur en fonction de l'angle selectionne ; IF TOTAL((*par).wactang) NE 0 AND (((*par).wchan/100) MOD 2) EQ 1 THEN BEGIN window,4,xsize=300,ysize=200,TITLE='Directional Signatures',XPOS=(*par).tlb_size[0]+200+2*(*par).inter,YPOS=(*par).inter ip = (*par).wchan MOD 100 IF ((*par).wchan/100) EQ 1 THEN Plot_signatures,*par, prod.D_par[ip], $ (*(*(*pstate).wstrTab).wSZA )[ix,iy,*], $ (*(*(*pstate).wstrTab).wVZA )[ix,iy,*], $ (*(*(*pstate).wstrTab).wAZI )[ix,iy,*], $ (*struc.wDtab[ip])[ix,iy,*] IF ((*par).wchan/100) EQ 3 THEN BEGIN ip0 = (prod.Cd_par[ip]).p0 & ip1 = (prod.Cd_par[ip]).p1 & ip2 = (prod.Cd_par[ip]).p2 Plot_signatures,*par, prod.D_par[ip0], $ (*(*(*pstate).wstrTab).wSZA )[ix,iy,*], $ (*(*(*pstate).wstrTab).wVZA )[ix,iy,*], $ (*(*(*pstate).wstrTab).wAZI )[ix,iy,*], $ (*struc.wDtab[ip0])[ix,iy,*],$ P1=(*struc.wDtab[ip1])[ix,iy,*],NP1=(prod.D_par[ip1]).name,$ P2=(*struc.wDtab[ip2])[ix,iy,*],NP2=(prod.D_par[ip2]).name ENDIF ENDIF ; ; Cas particulier du fichier de suivi aerosol sur mer. On va tracer reflectance et reflectance polarisee ; Mesure et modele ; IF (*(*pstate).wstrProd).type EQ 'L2TOGV' THEN $ Plot_signatures_aerosol, *par, $ (*(*(*pstate).wstrTab).wSZA )[ix,iy,*], $ (*(*(*pstate).wstrTab).wVZA )[ix,iy,*], $ (*(*(*pstate).wstrTab).wAZI )[ix,iy,*], $ (*struc.wDtab[P[0]])[ix,iy,*],$ (*struc.wDtab[P[1]])[ix,iy,*],$ (*struc.wDtab[P[2]])[ix,iy,*],$ (*struc.wDtab[P[3]])[ix,iy,*],$ (*struc.wDtab[P[4]])[ix,iy,*],$ (*struc.wDtab[P[5]])[ix,iy,*],$ (*struc.wDtab[P[6]])[ix,iy,*],$ (*struc.wDtab[P[7]])[ix,iy,*], $ (*struc.wDtab[P[8]])[ix,iy,*],$ (*struc.wDtab[P[9]])[ix,iy,*],$ (*struc.wDtab[P[10]])[ix,iy,*],$ (*struc.wDtab[P[11]])[ix,iy,*] ; Cas particulier du fichier de suivi aerosol sur terre. On va tracer reflectance ; polarisee Mesure et modele ; IF (*(*pstate).wstrProd).type EQ 'L2TLGV' THEN $ Plot_signatures_aerosol_terre, *par, $ (*(*(*pstate).wstrTab).wSZA )[ix,iy,*], $ (*(*(*pstate).wstrTab).wVZA )[ix,iy,*], $ (*(*(*pstate).wstrTab).wAZI )[ix,iy,*], $ (*struc.wDtab[Q[6]])[ix,iy,*],$ (*struc.wDtab[Q[0]])[ix,iy,*],$ (*struc.wDtab[Q[1]])[ix,iy,*],$ (*struc.wDtab[Q[2]])[ix,iy,*],$ (*struc.wDtab[Q[3]])[ix,iy,*],$ (*struc.wDtab[Q[4]])[ix,iy,*],$ (*struc.wDtab[Q[5]])[ix,iy,*] jump_traces: ; ; On "elimine" la selection en remettant les valeurs de latc,lonc,fz a celles de la carte ; (*par).wlatc = (*par).wMapLatc (*par).wlonc = (*par).wMapLonc (*par).wsizeNS = (*par).wMapsizeNS (*par).wsizeWE = (*par).wMapsizeWE WIDGET_CONTROL,(*(*pstate).wstrWidg).wZoomB,SENSITIVE=0 ; Le bouton "zoom" est non sensible ENDIF ELSE BEGIN ;==================================================================================================== ; Ci dessous les actions dans le cas ou la souris a ete deplacee ;==================================================================================================== ; On trace le rectangle qui marque la zone selectionnee depuis le dernier "clic" WSET,(*par).wid DEVICE,DECOMPOSE=0 PLOT,[(*par).wZpos[0],(*par).wZpos[2],(*par).wZpos[2],(*par).wZpos[0],(*par).wZpos[0]], $ [(*par).wZpos[1],(*par).wZpos[1],(*par).wZpos[3],(*par).wZpos[3],(*par).wZpos[1]], $ xrange=[0.,(*par).wdxs-1],yrange=[0.,(*par).wdxs-1],$ COLOR=(*par).wNC+2,THICK=2,/NOERASE,xstyle=5,ystyle=5,/NORMAL,POS=[0.,0.,1.,1.] ; Traduction des coordonn�es curseur en coordonn�es donn�es ix1 = FIX(((*par).wZPos[0] - (*par).wMapPos[0])/(*par).wfz) iy1 = FIX(((*par).wZPos[1] - (*par).wMapPos[1])/(*par).wfz) ix2 = FIX(((*par).wZPos[2] - (*par).wMapPos[0])/(*par).wfz) iy2 = FIX(((*par).wZPos[3] - (*par).wMapPos[1])/(*par).wfz) ix1 = MIN( ([ix1,ix2]>0)<((*par).wnbc-1) ,MAX=ix2) ; Ces instructions sont pour prendre en compte des iy1 = MIN( ([iy1,iy2]>0)<((*par).wnbl-1) ,MAX=iy2) ; zones en dehors du trace, ou prises dans le mauvais sens iseq = (*par).wseq-(*par).wseqmin ; Si il existe des parametres directionnels, on trace la position angulaire des points observes IF prod.Nd_par GT 0 THEN BEGIN window,5,xsize=200,ysize=200,TITLE='Angular Positions',XPOS=(*par).tlb_size[0]+(*par).inter,YPOS=(*par).inter plot_BRDF, *par, $ (*(*(*pstate).wstrTab).wSZA )[ix1:ix2,iy1:iy2,*] * !RADEG, $ (*(*(*pstate).wstrTab).wVZA )[ix1:ix2,iy1:iy2,*] * !RADEG, $ (*(*(*pstate).wstrTab).wAZI )[ix1:ix2,iy1:iy2,*] * !RADEG,/MULT ENDIF ; ; On va faire un plot different suivant le contexte: ; Si on regarde un parametre non directionnel, ou si aucun angle de visualisation ; n'est selectionne, on plotte les histogrammes des reflectances. ; Sinon [parametre directionnel], on trace la signature angulaire fonction de cet angle IF TOTAL( (*par).wactang) EQ 0 OR (*par).wchan/100 EQ 0 OR (*par).wchan/100 EQ 2 THEN BEGIN window,4,xsize=300,ysize=500,TITLE='Histograms',XPOS=(*par).tlb_size[0]+200+2*(*par).inter,YPOS=(*par).inter DEVICE,DECOMPOSE=0 ip = (*par).wchan MOD 100 CASE (*par).wchan/100 OF 0 : Plot_Histo,*par,prod.U_par[ip],(*struc.wUtab[ip])[ix1:ix2,iy1:iy2] 1 : Plot_Histo,*par,prod.D_par[ip],(*struc.wDtab[ip])[ix1:ix2,iy1:iy2,iseq] 2 : BEGIN ip0 = (prod.C_par[ip]).p0 & ip1 = (prod.C_par[ip]).p1 & ip2 = (prod.C_par[ip]).p2 Plot_Histo,*par,prod.U_par[ip0],(*struc.wUtab[ip0])[ix1:ix2,iy1:iy2], $ P1=(*struc.wUtab[ip1])[ix1:ix2,iy1:iy2], $ P2=(*struc.wUtab[ip2])[ix1:ix2,iy1:iy2], $ NP1=(prod.U_par[ip1]).name,NP2=(prod.U_par[ip2]).name END 3 : BEGIN ip0 = (prod.Cd_par[ip]).p0 & ip1 = (prod.Cd_par[ip]).p1 & ip2 = (prod.Cd_par[ip]).p2 Plot_Histo,*par,prod.D_par[ip0],(*struc.wDtab[ip0])[ix1:ix2,iy1:iy2,iseq], $ P1=(*struc.wDtab[ip1])[ix1:ix2,iy1:iy2,iseq], $ P2=(*struc.wDtab[ip2])[ix1:ix2,iy1:iy2,iseq], $ NP1=(prod.D_par[ip1]).name,NP2=(prod.D_par[ip2]).name END ENDCASE ENDIF ELSE BEGIN window,4,xsize=300,ysize=200,TITLE='Reflectance Signatures',XPOS=(*par).tlb_size[0]+200+2*(*par).inter,YPOS=(*par).inter ip = (*par).wchan MOD 100 IF ((*par).wchan/100) EQ 1 THEN Plot_signatures,*par, prod.D_par[ip], $ (*(*(*pstate).wstrTab).wSZA )[ix1:ix2,iy1:iy2,*], $ (*(*(*pstate).wstrTab).wVZA )[ix1:ix2,iy1:iy2,*], $ (*(*(*pstate).wstrTab).wAZI )[ix1:ix2,iy1:iy2,*], $ (*struc.wDtab[ip])[ix1:ix2,iy1:iy2,*],/MULT IF ((*par).wchan/100) EQ 3 THEN BEGIN ip0 = (prod.Cd_par[ip]).p0 & ip1 = (prod.Cd_par[ip]).p1 & ip2 = (prod.Cd_par[ip]).p2 Plot_signatures,*par, prod.D_par[ip0], $ (*(*(*pstate).wstrTab).wSZA )[ix1:ix2,iy1:iy2,*], $ (*(*(*pstate).wstrTab).wVZA )[ix1:ix2,iy1:iy2,*], $ (*(*(*pstate).wstrTab).wAZI )[ix1:ix2,iy1:iy2,*], $ (*struc.wDtab[ip0])[ix1:ix2,iy1:iy2,*], /MULT, $ P1=(*struc.wDtab[ip1])[ix1:ix2,iy1:iy2,*],NP1=(prod.D_par[ip1]).name, $ P2=(*struc.wDtab[ip2])[ix1:ix2,iy1:iy2,*],NP2=(prod.D_par[ip2]).name ENDIF ENDELSE ; ; Le bouton "zoom" est sensible ; WIDGET_CONTROL,(*(*pstate).wstrWidg).wZoomB,/SENSITIVE ENDELSE ; Fin du IF "deplace/non deplace" ENDIF ; Fin du IF "release" WSHOW,(*par).wid ; On remet la fenetre principale en avant END ; ����� END OF FENETRE_EVENT ����� ;================================================================================= FUNCTION bin,n ; Cette fonction retourne la version binaire d'un entier long ;--------------------------------------------------------------------------------- s='' FOR i=0, 15 DO BEGIN k = n MOD 2 s = s + STRING(k,FORMAT='(I1.1)') n = n/2 IF i MOD 4 EQ 3 THEN s = s + ' ' ENDFOR RETURN,s END ;================================================================================= PRO make_palette,NC,ipal ; G�n�re une palette de couleur adaptee a la visualisation 8 bits ; 0 pour une palette grise, 1 pour une palette "rainbow", plus quelques valeurs specifiques (Blanc, Noir, Rouge, Vert ;--------------------------------------------------------------------------------- IF ipal EQ 0 THEN BEGIN r = BYTE(INDGEN(NC+5)*255./float(NC)) r[0]=0 & r[nc+4]=255 g = r & b=r r[nc+1] = 255 g[nc+2] = 255 b[nc+3] = 255 tvlct,r,g,b ENDIF IF ipal EQ 1 THEN BEGIN H = BYTE((NC-INDGEN(NC+5))*255/NC) L = FLTARR(NC+5)+0.5 S = FLTARR(NC+5)+1 L[0] = 0 H[NC+1] = 1 H[NC+2] = 120 H[NC+3] = 250 L[NC+4] = 1. tvlct,h,l,s,/HLS ENDIF ; !P.COLOR = 0 !P.BACKGROUND=NC+4 END ;================================================================================= PRO Make_Visu,pstate ; Genere le tableau de visualisation ;--------------------------------------------------------------------------------- par = (*pstate).wstrParam prod = *(*pstate).wstrProd tabl = *(*pstate).wstrTab cha_typ = (*par).wchan/100 & parnum = (*par).wchan MOD 100 CASE cha_typ OF 0 : BEGIN param = prod.U_par[parnum] ptrtab = Tabl.wUtab[parnum] END 1 : BEGIN param = prod.D_par[parnum] ptrtab = Tabl.wDtab[parnum] END 2 : BEGIN param = prod.U_par[(prod.C_par[parnum]).p1] ptrtab = Tabl.wUtab[(prod.C_par[parnum]).p1] END 3 : BEGIN param = prod.D_par[(prod.Cd_par[parnum]).p1] ptrtab = Tabl.wDtab[(prod.Cd_par[parnum]).p1] END ENDCASE ; Recherche automatiques des valeurs min et max de la palette de couleur ; On prend l'histogramme cumule a 5% et 95% IF (*par).wauto THEN BEGIN valid = where(*ptrtab NE param.unvalid AND *ptrtab NE param.satur AND *ptrtab NE param.dummy, count) IF count EQ 0 THEN BEGIN vmin=0 & vmax=100 ENDIF ELSE BEGIN histo = HISTOGRAM((*ptrtab)[valid]*1,OMIN=omin) Nel = N_ELEMENTS(histo) IF Nel LE 3 THEN BEGIN ; Cas particulier lorsque tres peu de valeurs dans l'histogramme vmin = 0 & vmax = (Nel-1)>1 ENDIF ELSE BEGIN chisto = histo FOR i=1l, Nel-1 DO chisto[i] = chisto[i-1] + histo[i] vm = 0.05 * chisto[Nel-1] vmin = 0l & WHILE (chisto[vmin] LT vm) DO vmin=vmin+1 vm = 0.95 * chisto[Nel-1] vmax = 0l & WHILE (chisto[vmax] LT vm) DO vmax=vmax+1 IF vmin EQ vmax THEN BEGIN vmin = 0 & vmax = (Nel-1)>1 ENDIF ENDELSE vmin = vmin + omin vmax = vmax + omin ENDELSE (*par).wvmin = vmin*param.slope + param.offset (*par).wvmax = vmax*param.slope + param.offset ; On affiche les valeurs trouvees dans les boites appropri�es WIDGET_CONTROL,(*(*pstate).wstrWidg).wMinF,SET_VALUE=(*par).wvmin WIDGET_CONTROL,(*(*pstate).wstrWidg).wMaxF,SET_VALUE=(*par).wvmax ENDIF ELSE BEGIN ; Ici, les valeurs sont celles choisies par l'utilisateur vmax = ((*par).wvmax - param.offset) / param.slope vmin = ((*par).wvmin - param.offset) / param.slope ENDELSE ; rr est la gamme de variation utile. On la met superieure a 1 pour de pas risquer de diviser par zero rr = float(vmax-vmin) > 1. ; ; On fabrique le tableau de visualisation. Different suivant les options ; IF cha_typ EQ 0 OR cha_typ EQ 1 THEN BEGIN ; Ici, parametre simple (pas de composition coloree) vvisu = BYTE( ((1+(*ptrtab-vmin)/rr*((*par).wNC-1)) < (*par).wNC)>1) unvalid = where(*ptrtab EQ param.unvalid OR *ptrtab EQ param.dummy,count) IF count NE 0 THEN vvisu[unvalid] = (*par).wNC+4 ENDIF IF cha_typ EQ 2 THEN BEGIN ; Composition coloree d'un parametre non-directionnel vvisu = BYTARR((*par).wnbc*(*par).wnbl,3) fac = ((*par).wNC-1)/rr vvisu[*,0] = BYTE( ((1+(*Tabl.wUtab[(prod.C_par[parnum]).p0]-vmin)*fac) < (*par).wNC)>1) vvisu[*,1] = BYTE( ((1+(*Tabl.wUtab[(prod.C_par[parnum]).p1]-vmin)*fac) < (*par).wNC)>1) vvisu[*,2] = BYTE( ((1+(*Tabl.wUtab[(prod.C_par[parnum]).p2]-vmin)*fac) < (*par).wNC)>1) unvalid = where(*(Tabl.wUtab[(prod.C_par[parnum]).p0]) EQ (prod.U_par[(prod.C_par[parnum]).p0]).unvalid OR $ *(Tabl.wUtab[(prod.C_par[parnum]).p0]) EQ (prod.U_par[(prod.C_par[parnum]).p0]).dummy ,count) IF count NE 0 THEN vvisu[unvalid,0] = 0 unvalid = where(*(Tabl.wUtab[(prod.C_par[parnum]).p1]) EQ (prod.U_par[(prod.C_par[parnum]).p1]).unvalid OR $ *(Tabl.wUtab[(prod.C_par[parnum]).p1]) EQ (prod.U_par[(prod.C_par[parnum]).p1]).dummy ,count) IF count NE 0 THEN vvisu[unvalid,1] = 0 unvalid = where(*(Tabl.wUtab[(prod.C_par[parnum]).p2]) EQ (prod.U_par[(prod.C_par[parnum]).p2]).unvalid OR $ *(Tabl.wUtab[(prod.C_par[parnum]).p2]) EQ (prod.U_par[(prod.C_par[parnum]).p2]).dummy ,count) IF count NE 0 THEN vvisu[unvalid,2] = 0 vvisu = REFORM(vvisu,(*par).wnbc,(*par).wnbl,3) ENDIF IF cha_typ EQ 3 THEN BEGIN vvisu = BYTARR((*par).wnbc * (*par).wnbl * ((*par).wseqmax-(*par).wseqmin+1l),3) fac = ((*par).wNC-1)/rr vvisu[*,0] = BYTE( ((1+(*Tabl.wDtab[(prod.Cd_par[parnum]).p0]-vmin)*fac) < (*par).wNC)>1) vvisu[*,1] = BYTE( ((1+(*Tabl.wDtab[(prod.Cd_par[parnum]).p1]-vmin)*fac) < (*par).wNC)>1) vvisu[*,2] = BYTE( ((1+(*Tabl.wDtab[(prod.Cd_par[parnum]).p2]-vmin)*fac) < (*par).wNC)>1) unvalid = where(*(Tabl.wDtab[(prod.Cd_par[parnum]).p0]) EQ (prod.D_par[(prod.Cd_par[parnum]).p0]).unvalid OR $ *(Tabl.wDtab[(prod.Cd_par[parnum]).p0]) EQ (prod.D_par[(prod.Cd_par[parnum]).p0]).dummy ,count) IF count NE 0 THEN vvisu[unvalid,0] = 0 unvalid = where(*(Tabl.wDtab[(prod.Cd_par[parnum]).p1]) EQ (prod.D_par[(prod.Cd_par[parnum]).p1]).unvalid OR $ *(Tabl.wDtab[(prod.Cd_par[parnum]).p1]) EQ (prod.D_par[(prod.Cd_par[parnum]).p1]).dummy ,count) IF count NE 0 THEN vvisu[unvalid,1] = 0 unvalid = where(*(Tabl.wDtab[(prod.Cd_par[parnum]).p2]) EQ (prod.D_par[(prod.Cd_par[parnum]).p2]).unvalid OR $ *(Tabl.wDtab[(prod.Cd_par[parnum]).p2]) EQ (prod.D_par[(prod.Cd_par[parnum]).p2]).dummy ,count) IF count NE 0 THEN vvisu[unvalid,2] = 0 vvisu = REFORM(vvisu,(*par).wnbc,(*par).wnbl,(*par).wseqmax-(*par).wseqmin+1,3) ENDIF *Tabl.wvvisu = vvisu END ;================================================================================= FUNCTION Find_Angles,SZA,VZA,AZI ; Determination d'un fond de carte donnant les isolignes ; INPUT : SZA, VZA, AZI : Tableaux des angles POLDER en binaires ; SORTIE : ptrangles : Tableau de pointeur sur des adresses ou sont stoquees des ; structures qui permettent de tracer les angles ;--------------------------------------------------------------------------------- FORWARD_FUNCTION isoc phase = ACOS(COS(SZA)*COS(VZA)+SIN(SZA)*SIN(VZA)*COS(AZI)) glit = ACOS(COS(SZA)*COS(VZA)-SIN(SZA)*SIN(VZA)*COS(AZI)) unvalid = WHERE(SZA EQ -99., count) IF count NE 0 THEN BEGIN phase[unvalid] = -99. glit [unvalid] = -99. ENDIF ; ; ptrangles est un tableau de pointeur sur des structures qui vont permettre de ; dessiner les angles ; s = SIZE(SZA) ptrangles = PTRARR(4,s[3]) FOR iseq = 0,s[3]-1 DO BEGIN ptrangles[0,iseq] = isoc(REFORM(VZA [*,*,iseq]),(INDGEN( 6)+1)*10*!DTOR) ptrangles[1,iseq] = isoc(REFORM(AZI [*,*,iseq]), [180.]*!DTOR) ptrangles[2,iseq] = isoc(REFORM(phase[*,*,iseq]),(INDGEN(14)+1)*10*!DTOR) ptrangles[3,iseq] = isoc(REFORM(glit [*,*,iseq]),(INDGEN( 7)+1)*10*!DTOR) ENDFOR RETURN, ptrangles END ;================================================================================= FUNCTION isoc,dat,values ; Genere une carte d'isocontours a partir du tableau 2D dat, aux valeurs "values" ;--------------------------------------------------------------------------------- dat2 = dat unvalid = WHERE(dat EQ -99., count) IF count/FLOAT(N_ELEMENTS(dat)) GT 0.75 OR FLOAT(!VERSION.RELEASE) LT 5.3 THEN BEGIN beg = INTARR(3) & x = FLTARR(2) RETURN,PTR_NEW({Nvert:0,Beg:beg,X:x,Y:x}) ENDIF IF count NE 0 THEN dat2[unvalid]=!VALUES.F_NAN dat2 = SMOOTH(dat2,5,/Nan) isocontour,dat2,outverts,outconn,C_VALUE=values IF N_ELEMENTS(outconn) LT 2 THEN BEGIN beg = INTARR(3) & x = FLTARR(2) resu = {Nvert:0,Beg:beg,X:x,Y:x} ENDIF ELSE BEGIN Nmax = 10000 beg = INTARR(Nmax) n=0 & i=0 & nbeg=0 WHILE n LE (N_ELEMENTS(outconn)-1) DO BEGIN beg[i] = nbeg ll = outconn[n] i = i + 1 n = n + ll + 1 nbeg = nbeg+ll ENDWHILE beg[i] = nbeg beg = beg[0:i] ; ; Les commandes ci dessous ont pour but d'eliminer les traits disgracieux ; resultant de la procedure d'isocontour X = REFORM(outverts[0,*]) Y = REFORM(outverts[1,*]) N = N_ELEMENTS(X) IF N LE 1 THEN GOTO, jump dist = ABS(X[0:N-2]-X[1:N-1])+ABS(Y[0:N-2]-Y[1:N-1]) bb = WHERE(dist GE 10., count)+1 IF count NE 0 THEN BEGIN Beg = [Beg,bb] Beg = Beg[UNIQ(Beg, SORT(Beg))] i = N_ELEMENTS(Beg)-1 ENDIF ; On definit une structure qui contient toutes les infos pour tracer les angles jump: resu = {Nvert:i,Beg:beg,X:X,Y:Y} ENDELSE RETURN,PTR_NEW(resu) END ;================================================================================= PRO Extract_Data,ptPix,pstate ; On lit les donnees "pixels" et on en extrait les valeurs sequence par sequence ; Les tableaux non-directionnels sont dans les tableaux rep�r�s par les pointeurs wUtab[i] ; Les tableaux directionnels sont dans les tableaux rep�r�s par les pointeurs wDtab[i] ; Si les valeurs directionnelles existe, il faut les tableaux SZA, VZA et AZI, rep�r�s par les pointeurs ; wSZA, wVZA et wAZI ;--------------------------------------------------------------------------------- FORWARD_FUNCTION Find_Angles par = *(*pstate).wstrparam prod = *(*pstate).wStrProd ptrtab = (*pstate).wStrTab NumbDir=14l IF par.parasol EQ 1 THEN NumbDir=16l IF par.parasol EQ 2 THEN NumbDir=26l ; ; On separe le tableau en parametres directionnels et non directionnels ; NonDir = (*ptPix)[ 0: prod.Nbyte_nd-1,*,*] IF prod.Nd_par NE 0 THEN $ Dir = REFORM((*ptPix)[prod.Nbyte_nd:prod.Nbyte_nd+NumbDir*prod.Nbyte_d-1,*,*],prod.Nbyte_d,NumbDir* par.wnbc * par.wnbl) PTR_FREE,ptpix ; On libere la memoire ; ; On rep�re les pixels "vide" ; vide = WHERE((FIX(NonDir[0,*,*]) + FIX(NonDir[1,*,*]) + $ FIX(NonDir[2,*,*]) + FIX(NonDir[3,*,*])) EQ 0,Nvide) ; Si tous les pixels sont vides, on arrete ; IF Nvide EQ (par.wnbc*par.wnbl) THEN BEGIN PRINT,' Aucune mesure valide' (*(*pstate).wstrparam).wseqmax=-99 RETURN ENDIF ELSE (*(*pstate).wstrparam).wseqmax=0 ; ; Lecture des parametres non-directionnels. 1 ou 2 octets a lire selon les parametres ; FOR i = 0, prod.Nu_par-1 DO BEGIN CASE (prod.u_par[i]).size OF 1 : tempo = REFORM(NonDir[(prod.u_par[i]).fi_by ,*,*] ,par.wnbc,par.wnbl) 2 : tempo = REFORM(NonDir[(prod.u_par[i]).fi_by ,*,*]*256us + $ NonDir[(prod.u_par[i]).fi_by+1,*,*] ,par.wnbc,par.wnbl) -2 : tempo = REFORM(NonDir[(prod.u_par[i]).fi_by ,*,*]*256s + $ NonDir[(prod.u_par[i]).fi_by+1,*,*] ,par.wnbc,par.wnbl) 5 : tempo = REFORM(NonDir[(prod.u_par[i]).fi_by ,*,*] ,par.wnbc,par.wnbl) MOD 16b ; Ces deux lignes pour traiter -5 : tempo = REFORM(NonDir[(prod.u_par[i]).fi_by ,*,*] ,par.wnbc,par.wnbl) / 16b ; les parametres codes sur des demi octets ELSE : $ ; Cas particulier des paramatres binaires. Normalement entre 11 et 18 tempo= ( REFORM(NonDir[(prod.u_par[i]).fi_by ,*,*]) / (2^(prod.u_par[i].size-11)) ) MOD 2 ENDCASE IF Nvide NE 0 THEN tempo[vide] = (prod.u_par[i]).dummy ; En dehors de l'orbite, c'est vide PTR_FREE,(*ptrtab).wUtab[i] ; On lib�re la m�moire, puis on recupere le pointeur sur le tableau (*ptrtab).wUtab[i] = PTR_NEW(tempo) ENDFOR ; ; On lit les numeros de colonne et ligne. Utile pour se rep�rer ; PTR_FREE,(*ptrtab).wCol,(*ptrtab).wLin (*ptrtab).wLin = PTR_NEW(REFORM(NonDir[6,*,*]*256us + NonDir[7,*,*])) (*ptrtab).wCol = PTR_NEW(REFORM(NonDir[8,*,*]*256us + NonDir[9,*,*])) print,'=================================== NON-DIRECTIONAL PARAMETERS =========================================' print,' Name Min Max Unit ------ Unvalid ------ ------ Dummy ------ ------ Satur ------' fmt='(A14,2F7.1," ",A7,3(2I7," [",F4.1,"%] "))' FOR i=0, prod.Nu_par-1 DO BEGIN nn = WHERE(*(*ptrtab).wUtab[i] EQ prod.u_par[i].unvalid, Nunvalid) nn = WHERE(*(*ptrtab).wUtab[i] EQ prod.u_par[i].dummy , Ndummy) nn = WHERE(*(*ptrtab).wUtab[i] EQ prod.u_par[i].satur , Nsatur) fac=100./N_ELEMENTS(*(*ptrtab).wUtab[i]) valid = WHERE(*(*ptrtab).wUtab[i] NE prod.u_par[i].unvalid AND $ *(*ptrtab).wUtab[i] NE prod.u_par[i].dummy AND $ *(*ptrtab).wUtab[i] NE prod.u_par[i].satur ,count) IF count NE 0 THEN vmin=MIN((*(*ptrtab).wUtab[i])[valid],MAX=vmax) ELSE BEGIN vmin=0 & vmax=0 ENDELSE print,prod.u_par[i].name,vmin*prod.u_par[i].slope+prod.u_par[i].offset, $ vmax*prod.u_par[i].slope+prod.u_par[i].offset,prod.u_par[i].unit,$ prod.u_par[i].unvalid,Nunvalid,Nunvalid*fac, $ prod.u_par[i].dummy ,Ndummy ,Ndummy *fac, $ prod.u_par[i].satur ,Nsatur ,Nsatur *fac, $ format=fmt ENDFOR ; ; Si le produit ne possede que des parametres non directionnels, on a termine ; IF prod.Nd_par LE 0 THEN RETURN ; ; Les donnees de Niveau 1, et 2-TE sont reprojetees sur les sequences. Pas les autres. IF prod.type EQ 'L1TBG1' OR STRMID(prod.type,0,6) EQ 'L2TLGA' THEN BEGIN SeqNum = REFORM(Dir[ 0,*]) seqmin = MIN(SeqNum[WHERE(SeqNum NE 0 AND SeqNum LT 200)],MAX=seqmax) (*(*pstate).wStrParam).wseqmin = seqmin (*(*pstate).wStrParam).wseqmax = seqmax (*(*pstate).wStrParam).wseq = (seqmin+seqmax)/2 ENDIF ELSE BEGIN (*(*pstate).wStrParam).wseqmin = 0 (*(*pstate).wStrParam).wseqmax = NumbDir-1 (*(*pstate).wStrParam).wseq = 0 ENDELSE ; Initialisation de la sequence courante a la sequence centrale WIDGET_CONTROL,(*(*pstate).wStrWidg).wSeqS,SET_VALUE=(*(*pstate).wStrParam).wseq , $ SET_SLIDER_MIN=(*(*pstate).wStrParam).wseqmin, $ SET_SLIDER_MAX=(*(*pstate).wStrParam).wseqmax Nseq = (*(*pstate).wStrParam).wseqmax - (*(*pstate).wStrParam).wseqmin + 1 ; ; Definition des tableaux directionnels ; FOR i = 0, prod.Nd_par-1 DO BEGIN PTR_FREE,(*ptrTab).wDtab[i] CASE (prod.d_par[i]).size OF 2 : (*ptrTab).wDtab[i] = PTR_NEW(UINTARR(par.wnbc*par.wnbl,Nseq)+UINT(prod.d_par[i].dummy)) -2 : (*ptrTab).wDtab[i] = PTR_NEW( INTARR(par.wnbc*par.wnbl,Nseq)+ FIX(prod.d_par[i].dummy)) ELSE: (*ptrTab).wDtab[i] = PTR_NEW( BYTARR(par.wnbc*par.wnbl,Nseq)+BYTE(prod.d_par[i].dummy)) ENDCASE ENDFOR SZA = UINTARR(par.wnbc*par.wnbl,Nseq) VZA = UINTARR(par.wnbc*par.wnbl,Nseq) AZI = UINTARR(par.wnbc*par.wnbl,Nseq) IF prod.type EQ 'L1TBG1' THEN BEGIN ; Ici, on analyse le DQX du niveau 1 Ndir = NumbDir DQX = UINTARR(par.wnbc,par.wnbl,Ndir) FOR i=0, Ndir-1 DO DQX[*,*,i] = REFORM(NonDir[13+2*i,*,*]*256us + $ NonDir[14+2*i,*,*] ,par.wnbc,par.wnbl) PTR_FREE, (*ptrTab).wDQX (*ptrTab).wDQX = PTR_NEW(DQX) ENDIF IF prod.type EQ 'L1TBG1' THEN GOTO, jump_N1 ; ; Lecture des donn�es directionelles, s�quence par s�quence. Note : Les donnees de Niveau 1, et 2-TE sont reprojetees ; sur les sequences. Pas les autres. IF STRMID(prod.type,0,6) EQ 'L2TLGA' THEN BEGIN FOR iseq = 0, Nseq-1 DO BEGIN valid = WHERE(SeqNum EQ (iseq+seqmin),count) IF count EQ 0 THEN GOTO, nextseq FOR i = 0, prod.Nd_par-1 DO BEGIN CASE (prod.d_par[i]).size OF 1 : (*(*ptrTab).wDtab[i])[valid/NumbDir,iseq] = REFORM(Dir[(prod.d_par[i]).fi_by ,valid]) 2 : (*(*ptrTab).wDtab[i])[valid/NumbDir,iseq] = REFORM(Dir[(prod.d_par[i]).fi_by ,valid]*256us + $ Dir[(prod.d_par[i]).fi_by+1,valid]) -2 : (*(*ptrTab).wDtab[i])[valid/NumbDir,iseq] = REFORM(Dir[(prod.d_par[i]).fi_by ,valid]*256s + $ Dir[(prod.d_par[i]).fi_by+1,valid] ) ENDCASE ENDFOR NonDir = REFORM(NonDir,25,par.wnbc*par.wnbl) SZA [valid/14,iseq] = NonDir[21,valid/NumbDir]*256us + NonDir[22,valid/NumbDir] VZA [valid/14,iseq] = Dir[ 1,valid]*256us + Dir[ 2,valid] AZI [valid/14,iseq] = Dir[ 3,valid]*256us + Dir[ 4,valid] nextseq: ENDFOR ENDIF ELSE BEGIN ; Dans les autres cas, c'est beaucoup plus simple. On garde la structure sur NumbDir directions Dir = REFORM( Dir,prod.Nbyte_d,NumbDir, par.wnbc * par.wnbl) NonDir = REFORM(NonDir,prod.Nbyte_nd,par.wnbc*par.wnbl) FOR iseq = 0, Nseq-1 DO BEGIN FOR i = 0, prod.Nd_par-1 DO BEGIN CASE (prod.d_par[i]).size OF 1 : (*(*ptrTab).wDtab[i])[*,iseq] = REFORM(Dir[(prod.d_par[i]).fi_by ,iseq,*]) 2 : (*(*ptrTab).wDtab[i])[*,iseq] = REFORM(Dir[(prod.d_par[i]).fi_by ,iseq,*]*256us + $ Dir[(prod.d_par[i]).fi_by+1,iseq,*] ) -2 : (*(*ptrTab).wDtab[i])[*,iseq] = REFORM(Dir[(prod.d_par[i]).fi_by ,iseq,*]*256s + $ Dir[(prod.d_par[i]).fi_by+1,iseq,*] ) 5 : (*(*ptrTab).wDtab[i])[*,iseq] = REFORM(Dir[(prod.d_par[i]).fi_by ,iseq,*])/16b ; Ces deux lignes pour traiter -5 : (*(*ptrTab).wDtab[i])[*,iseq] = REFORM(Dir[(prod.d_par[i]).fi_by ,iseq,*]) MOD 16b ; les parametres codes sur des demi octets ENDCASE IF Nvide NE 0 THEN (*(*ptrTab).wDtab[i])[vide,iseq] = prod.d_par[i].dummy ; En dehors de l'orbite, c'est vide ENDFOR IF prod.type EQ 'L2TOGA' OR prod.type EQ 'L2TOGAo' OR prod.type EQ 'L2TOGV' OR prod.type EQ 'L2TLGV' THEN BEGIN SZA [*,iseq] = NonDir[17,*]*256us + NonDir[18,*] VZA [*,iseq] = Dir[ 0,iseq,*]*256us + Dir[ 1,iseq,*] AZI [*,iseq] = Dir[ 2,iseq,*]*256us + Dir[ 3,iseq,*] ENDIF IF prod.type EQ 'L2TOGU' THEN BEGIN SZA [*,iseq] = NonDir[13,*]*256us + NonDir[14,*] VZA [*,iseq] = Dir[ 0,iseq,*]*256us + Dir[ 1,iseq,*] AZI [*,iseq] = Dir[ 2,iseq,*]*256us + Dir[ 3,iseq,*] ENDIF IF prod.type EQ 'L2TRGB' OR prod.type EQ 'L2TRGBo' THEN BEGIN SZA [*,iseq] = NonDir[20,*] VZA [*,iseq] = Dir[ 0,iseq,*] AZI [*,iseq] = Dir[ 1,iseq,*] ENDIF ENDFOR ENDELSE ; ; Conversion des angles en radians, et passage par pointeur ; CASE STRMID(prod.type,0,6) OF 'L2TLGA' : BEGIN facs= 0.1*!DTOR & facv= 0.1*!DTOR & faca= 0.1*!DTOR END 'L2TLGV' : BEGIN facs= 0.1*!DTOR & facv= 0.1*!DTOR & faca= 0.1*!DTOR END 'L2TOGA' : BEGIN facs= 0.1*!DTOR & facv= 0.1*!DTOR & faca= 0.2*!DTOR END 'L2TOGV' : BEGIN facs= 0.1*!DTOR & facv= 0.1*!DTOR & faca= 0.2*!DTOR END 'L2TOGU' : BEGIN facs= 0.1*!DTOR & facv= 0.1*!DTOR & faca= 0.2*!DTOR END 'L2TRGB' : BEGIN facs= 1. & facv= 0.5*!DTOR & faca= 1.5*!DTOR END ENDCASE SZA = REFORM(SZA*facs,par.wnbc,par.wnbl,Nseq) VZA = REFORM(VZA*facv,par.wnbc,par.wnbl,Nseq) AZI = REFORM(AZI*faca,par.wnbc,par.wnbl,Nseq) ; Cas tres particulier du produit BR... IF STRMID(prod.type,0,6) EQ 'L2TRGB' THEN BEGIN AZI = AZI - !PI SZA = ACOS(SZA*4.E-3 + 0.2) ENDIF unval = WHERE(SZA LE 0. OR VZA LE 0. OR VZA GT !PI/2.,count) IF count NE 0 THEN BEGIN SZA[unval] = -99. VZA[unval] = -99. AZI[unval] = -99. ENDIF PTR_FREE,(*ptrTab).wSZA,(*ptrTab).wVZA,(*ptrTab).wAZI (*ptrTab).wSZA = PTR_NEW(SZA) (*ptrTab).wVZA = PTR_NEW(VZA) (*ptrTab).wAZI = PTR_NEW(AZI) FOR i = 0, prod.Nd_par-1 DO *(*(*pstate).wStrTab).wDtab[i] = REFORM(*(*ptrTab).wDtab[i],par.wnbc,par.wnbl,Nseq) IF STRMID(prod.type,1,1) NE 1 THEN GOTO, jump_N2 jump_N1 : ;==================================================================================== ;======== PARTIE SPECIFIQUE AU NIVEAU 1 (Calcul de la polarisation ============ ;==================================================================================== fac = 1.5E-3*!DTOR Dir = REFORM(Dir,prod.Nbyte_d,NumbDir*par.wnbc*par.wnbl) pSZA =((Dir[ 5,*]*256us+ Dir[ 6,*])>1us)*fac ; On met sup a 1 pour eviter des divisions par zero plus bas pVZA = (Dir[ 7,*]*256us+ Dir[ 8,*])*fac pAZI = (Dir[ 9,*]*256us+ Dir[10,*])*fac*4 DVzC = (Dir[11,*]*1) & DVzC = ((DVzC+128) MOD 256) - 128 & rDVzC=DVzC*1.6E-3*!DTOR DVzS = (Dir[12,*]*1) & DVzS = ((DVzS+128) MOD 256) - 128 & rDVzS=DVzS*1.6E-3*!DTOR ; ---- On commence par calculer 443 nm X = pVZA*COS(pAZI) -6.*rDVzC Y = pVZA*SIN(pAZI) -6.*rDVzS VZAc = SQRT(X*X+Y*Y) AZIc = ATAN(Y,X) alpha = 2.*ATAN(sin(AZIc)/(SIN(VZAc)/TAN(pSZA)-COS(VZAc)*COS(AZIc))) Q = Dir[31,*]*256s + Dir[32,*] U = Dir[37,*]*256s + Dir[38,*] Xi443 = ((ATAN(U,Q) - alpha)/2.*!RADEG+360.) MOD 180. Lp443 = FIX(-Q*COS(alpha) - U*SIN(alpha)) unvalid = WHERE(ABS(Q) EQ 32767,count) IF count NE 0 THEN BEGIN Lp443[unvalid]=Q[unvalid] & Xi443[unvalid]=-327.67 ENDIF ; ---- Puis 670 nm. Pas de correction des angles alpha = 2.*ATAN(sin(pAZI )/(SIN(pVZA )/TAN(pSZA)-COS(pVZA )*COS(pAZI ))) Q = Dir[33,*]*256s + Dir[34,*] U = Dir[39,*]*256s + Dir[40,*] Xi670 = ((ATAN(U,Q) - alpha)/2.*!RADEG+360.) MOD 180. Lp670 = FIX(-Q*COS(alpha) - U*SIN(alpha)) unvalid = WHERE(ABS(Q) EQ 32767,count) IF count NE 0 THEN BEGIN Lp670[unvalid]=Q[unvalid] & Xi670[unvalid]=-327.67 ENDIF ; ---- Enfin 865 nm X = pVZA*COS(pAZI) +6.*rDVzC Y = pVZA*SIN(pAZI) +6.*rDVzS VZAc = SQRT(X*X+Y*Y) AZIc = ATAN(Y,X) alpha = 2.*ATAN(sin(AZIc)/(SIN(VZAc)/TAN(pSZA)-COS(VZAc)*COS(AZIc))) Q = Dir[35,*]*256s + Dir[36,*] U = Dir[41,*]*256s + Dir[42,*] Xi865 = ((ATAN(U,Q) - alpha)/2.*!RADEG+360.) MOD 180. Lp865 = FIX(-Q*COS(alpha) - U*SIN(alpha)) unvalid = WHERE(ABS(Q) EQ 32767,count) IF count NE 0 THEN BEGIN Lp865[unvalid]=Q[unvalid] & Xi865[unvalid]=-327.67 ENDIF ; ; On fabrique les tableaux de reflectance polarisee ; SZA = FLOAT(SZA) & VZA = FLOAT(VZA) & AZI = FLOAT(AZI) FOR iseq = 0, Nseq-1 DO BEGIN valid = WHERE(SeqNum EQ (iseq+seqmin),count) IF count EQ 0 THEN GOTO, nextseq2 SZA [valid/NumbDir,iseq] = pSZA[valid] VZA [valid/NumbDir,iseq] = pVZA[valid] AZI [valid/NumbDir,iseq] = pAZI[valid] FOR i = 0,prod.Nd_par-7 DO $ (*(*ptrTab).wDtab[i])[valid/NumbDir,iseq] = REFORM(Dir[(prod.d_par[i]).fi_by ,valid]*256s + $ Dir[(prod.d_par[i]).fi_by+1,valid] ) (*(*ptrTab).wDtab[prod.Nd_par-6])[valid/NumbDir,iseq] = Lp443[valid] (*(*ptrTab).wDtab[prod.Nd_par-5])[valid/NumbDir,iseq] = Lp670[valid] (*(*ptrTab).wDtab[prod.Nd_par-4])[valid/NumbDir,iseq] = Lp865[valid] (*(*ptrTab).wDtab[prod.Nd_par-3])[valid/NumbDir,iseq] = FIX(Xi443[valid]*100.) (*(*ptrTab).wDtab[prod.Nd_par-2])[valid/NumbDir,iseq] = FIX(Xi670[valid]*100.) (*(*ptrTab).wDtab[prod.Nd_par-1])[valid/NumbDir,iseq] = FIX(Xi865[valid]*100.) nextseq2: ENDFOR ; ; On passe tout en reflectances ; fac = 1./COS(SZA) FOR i = 0, prod.Nd_par-4 DO BEGIN valid = WHERE(ABS( *(*ptrTab).wDtab[i] ) NE 32767 ) (*(*ptrTab).wDtab[i])[valid] = (*(*ptrTab).wDtab[i])[valid] * fac[valid] ENDFOR FOR i = 0, prod.Nd_par-1 DO *(*(*pstate).wStrTab).wDtab[i] = REFORM(*(*ptrTab).wDtab[i],par.wnbc,par.wnbl,Nseq) unval = WHERE(SZA LE 0. OR VZA LE 0. OR VZA GT !PI/2.,count) IF count NE 0 THEN BEGIN SZA[unval] = -99. VZA[unval] = -99. AZI[unval] = -99. ENDIF SZA = REFORM(SZA,par.wnbc,par.wnbl,Nseq) VZA = REFORM(VZA,par.wnbc,par.wnbl,Nseq) AZI = REFORM(AZI,par.wnbc,par.wnbl,Nseq) PTR_FREE,(*ptrTab).wSZA,(*ptrTab).wVZA,(*ptrTab).wAZI (*ptrTab).wSZA = PTR_NEW(SZA) (*ptrTab).wVZA = PTR_NEW(VZA) (*ptrTab).wAZI = PTR_NEW(AZI) ; on r�cup�re les positions ou les angles de vue prennent des valeurs particulieres, et on passe le resultat en structure PTR_FREE,*(*ptrTab).wangstr tab_ptr_ang = Find_Angles(SZA,VZA,AZI) *(*ptrTab).wangstr = PTR_NEW(tab_ptr_ang) ;==================================================================================== ;=============== FIN DE LA PARTIE SPECIFIQUE AU NIVEAU 1 ===================== ;==================================================================================== jump_N2: ; ; Trac� des statistiques sur les produits ; print,'===================================== DIRECTIONAL PARAMETERS ============================================' print,' Name Min Max Unit ------ Unvalid ------ ------ Dummy ------ ------ Satur ------' nn = WHERE(SZA EQ -99.,Ndummy) & vmin = MIN(SZA[WHERE(SZA NE -99.)],MAX=vmax) print,'Sol. Zen Angle',vmin*!RADEG,vmax*!RADEG,'deg.',-999,0,0.,-99,Ndummy,Ndummy*100./N_ELEMENTS(SZA),-999,0,0.,format=fmt nn = WHERE(VZA EQ -99.,Ndummy) & vmin = MIN(VZA[WHERE(VZA NE -99.)],MAX=vmax) print,'View Zen Angle',vmin*!RADEG,vmax*!RADEG,'deg.',-999,0,0.,-99,Ndummy,Ndummy*100./N_ELEMENTS(SZA),-999,0,0.,format=fmt nn = WHERE(AZI EQ -99.,Ndummy) & vmin = MIN(AZI[WHERE(AZI NE -99.)],MAX=vmax) print,'Rel. Azim. Ang',vmin*!RADEG,vmax*!RADEG,'deg.',-999,0,0.,-99,Ndummy,Ndummy*100./N_ELEMENTS(SZA),-999,0,0.,format=fmt FOR i=0, prod.Nd_par-1 DO BEGIN nn = WHERE(*(*ptrtab).wDtab[i] EQ prod.d_par[i].unvalid, Nunvalid) nn = WHERE(*(*ptrtab).wDtab[i] EQ prod.d_par[i].dummy , Ndummy) nn = WHERE(*(*ptrtab).wDtab[i] EQ prod.d_par[i].satur , Nsatur) fac=100./N_ELEMENTS(*(*ptrtab).wDtab[i]) valid = WHERE(*(*ptrtab).wDtab[i] NE prod.d_par[i].unvalid AND $ *(*ptrtab).wDtab[i] NE prod.d_par[i].dummy AND $ *(*ptrtab).wDtab[i] NE prod.d_par[i].satur ,count) IF count NE 0 THEN vmin=MIN((*(*ptrtab).wDtab[i])[valid],MAX=vmax) ELSE BEGIN vmin=0 & vmax=0 ENDELSE print,prod.d_par[i].name,vmin*prod.d_par[i].slope+prod.d_par[i].offset, $ vmax*prod.d_par[i].slope+prod.d_par[i].offset,prod.d_par[i].unit,$ prod.d_par[i].unvalid,Nunvalid,Nunvalid*fac, $ prod.d_par[i].dummy ,Ndummy ,Ndummy *fac, $ prod.d_par[i].satur ,Nsatur ,Nsatur *fac, $ format=fmt ENDFOR END ;================================================================================= FUNCTION Get_Pixels,pstate,NlinMax ; ; Extrait les pixels d'un produit POLDER defini par son chemin filein ; latcen et loncen sont les coordonn�es du point central [degres] ; Nlin est le nombre de lignes de la zone selectionn�e ; Ncol est le nombre de colonnes de la zone s�lectionn�e (par defaut egal a Nlin). ;--------------------------------------------------------------------------------- prod = *(*pstate).wStrProd par = (*pstate).wStrParam ; ; Pour �viter les probl�mes, on impose une taille de zone correspondant a au moins 10 pixels ; IF (*par).wSizeNS LT 10./9.E-3/prod.resol THEN BEGIN (*par).wSizeNS = 10./9.E-3/prod.resol WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbLinF,SET_VALUE=ROUND((*par).wsizeNS) ENDIF IF (*par).wSizeWE LT 10./9.E-3/prod.resol THEN BEGIN (*par).wSizeWE = 10./9.E-3/prod.resol WIDGET_CONTROL,(*(*pstate).wstrWidg).wNbColF,SET_VALUE=ROUND((*par).wsizeWE) ENDIF latmin = (*par).wLatC - (*par).wSizeNS/2.*9.E-3 latmax = (*par).wLatC + (*par).wSizeNS/2.*9.E-3 RapSize = (*par).wSizeWE/float((*par).wSizeNS) NlinPol = FIX((latmax-latmin)*prod.resol) NcolPol = FIX((latmax-latmin)*RapSize*prod.resol) fz = (MAX([NlinPol,NcolPol])-1)/NlinMax + 1 linmax = FIX( prod.resol*(90.-latmin)-0.5*fz ) Nlin = NlinPol/fz Ncol = NcolPol/fz Nlinmax = 180*prod.resol rec_size = prod.Nbyte_tot pixels = BYTARR(rec_size,Ncol,Nlin) (*par).wnbc = Ncol (*par).wnbl = Nlin (*par).wfz = fz (*par).wsamp = fz ; ; On trouve le nombre de pixels par ligne Npix = *(*par).pNpix NpixSum = LONARR(Nlinmax) IF (*par).parasol NE 0 AND prod.type EQ 'L1TBG1' THEN BEGIN NpixSum[NlinMax-1] = 0 FOR i = NlinMax-2, 0, -1 DO NpixSum[i] = NpixSum[i+1]+ Npix[i+1] ENDIF ELSE BEGIN NpixSum[0] = 0 FOR i = 1, Nlinmax-1 DO NpixSum[i] = NpixSum[i-1]+ Npix[i-1] ENDELSE ; ; Ouverture du fichier de donn�es ; openr,lun,(*par).wfilein,/get_Lun,ERROR=err IF err NE 0 THEN BEGIN user_response=DIALOG_MESSAGE('Error when trying to open file '+(*par).wfilein) RETURN,PTR_NEW(pixels,/NO_COPY) ENDIF ; ; Boucle sur les lignes, lecture des donnees et extraction des colonnes ; FOR ilin = 0, Nlin-1 DO BEGIN linpol = linmax - ilin*fz IF linpol LT 0 OR linpol GE Nlinmax THEN GOTO, nextline IF Npix[linpol] EQ 0 THEN GOTO, nextline point_lun,lun,180+NpixSum[linpol]*rec_size data = bytarr(rec_size, Npix[linpol]) readu,lun,data col = REFORM(data[ 8,*]*256s + data[ 9,*]) lat = 90. - (linpol+0.5)/prod.resol NcolM = 2*ROUND(Nlinmax*COS(lat*!DTOR)) colcen = FIX((((*par).wlonc+180.) MOD 360.)/360.*NcolM) ; colcen va de 0 a NcolM-1 entre -180 et 180. colcor = (col-1-Nlinmax+ NcolM/2) MOD NcolM ; colcor va de 0 a NcolM-1 entre -180 et 180. dist = ((colcor-colcen + (3*NcolM)/2) MOD NcolM)-NcolM/2 IF (Ncol MOD 2) EQ 0 THEN $ valid = WHERE( (ABS(dist) LE fz*(Ncol/2)) AND ( ((dist+fz/2 ) MOD fz) EQ 0), count) $ ELSE valid = WHERE( (ABS(dist) LE fz*(Ncol/2)) AND ( ((dist ) MOD fz) EQ 0), count) IF count NE 0 THEN BEGIN indice = FIX(dist[valid]/float(fz) + Ncol/2.) ; Les 3 lignes ci dessus ont �t� v�rifi�es pixels[*,indice,ilin] = data[*,valid] ENDIF nextline: ENDFOR free_lun,lun RETURN,PTR_NEW(pixels,/NO_COPY) END ;============================================================================= FUNCTION Get_Pos_Orb,par ; Cette fonction retourne un tableau FLTARR[3,N] ; [0,*] sont les latitudes ; [1,*] sont les longitudes en bord Ouest de l'orbite ; [2,*] sont les longitudes en bord Est de l'orbite ; INPUT : Les parametres par. Sont utilies lonEq et Npix ; Cette fonction est bas�e sur une approximation, d�termin�e a partir d'une ; orbite de niveau 1. ;---------------------------------------------------------------------------- N = N_ELEMENTS(*(*par).pNpix) linmin=MIN(WHERE(*(*par).pNpix NE 0),MAX=linmax) latmax = FIX( 90.-(linmin+0.5)*180./N) latmin = FIX( 90.-(linmax+0.5)*180./N) Npos = (latmax-latmin+1) POS = FLTARR(3,Npos) lat = FLOAT(INDGEN(Npos)+latmin) POS[0,*] = lat IF (*par).parasol NE 0 THEN coef=[-6.30260,-0.210946,-0.00018232, 1.57610e-05, 2.62786e-08] $ ELSE coef=[-11.5435, 0.220568,0.000112140,-1.12869e-05,-9.21399e-08] loninf = (coef[0] + coef[1]*lat + coef[2]*lat^2 + coef[3]*lat^3 + coef[4]*lat^4)/COS(lat*!DTOR) > (-180.) lat = -lat & coef=-coef lonsup = (coef[0] + coef[1]*lat + coef[2]*lat^2 + coef[3]*lat^3 + coef[4]*lat^4)/COS(lat*!DTOR) < 180. POS[1,*] = loninf + (*par).wlonEq POS[2,*] = lonsup + (*par).wlonEq RETURN,POS END ;================================================================================ PRO Plot_Histo, par, prod, P0, P1=P1, P2=P2, NP1=NP1, NP2=NP2 ; Calcul et plot des histogrammes et histogrammes cumul�s ; Possibilite de superposer les histogrames de plusieurs parametres ;-------------------------------------------------------------------------------- valid = WHERE(P0 NE prod.unvalid AND P0 NE prod.satur AND P0 NE prod.dummy,count) IF count EQ 0 THEN RETURN sat = WHERE(P0 EQ prod.satur, Nsatur) vmin = MIN(P0[valid],MAX=vmax) IF KEYWORD_SET(P1) THEN BEGIN valid1 = WHERE(P1 NE prod.unvalid AND P1 NE prod.satur AND P1 NE prod.dummy,count) IF count EQ 0 THEN P1=0 ELSE BEGIN ; On ne peut rien faire avec ce parametre. On le de-valide sat1 = WHERE(P1 EQ prod.satur, Nsatur1) vmin1 = MIN(P1[valid1],MAX=vmax1) vmin = vminvmax1 ENDELSE ENDIF IF KEYWORD_SET(P2) THEN BEGIN valid2 = WHERE(P2 NE prod.unvalid AND P2 NE prod.satur AND P2 NE prod.dummy,count) IF count EQ 0 THEN P2=0 ELSE BEGIN ; On ne peut rien faire avec ce parametre. On le de-valide sat2 = WHERE(P2 EQ prod.satur, Nsatur2) vmin1 = MIN(P2[valid2],MAX=vmax1) vmin = vminvmax1 ENDELSE ENDIF box = (vmax-vmin)/300 + 1 histo0 = HISTOGRAM( P0[valid],min=vmin,max=vmax,bin=box) N = N_ELEMENTS(histo0) chisto0 = histo0 & FOR i=1, N-1 DO chisto0[i] = chisto0[i-1]+histo0[i] histo0 = float(histo0) & chisto0=chisto0/float(chisto0[N-1]+Nsatur )*100. Nmax = MAX(histo0) IF KEYWORD_SET(P1) THEN BEGIN histo1 = HISTOGRAM( P1[valid1],min=vmin,max=vmax,bin=box) chisto1 = histo1 & FOR i=1, N-1 DO chisto1[i] = chisto1[i-1]+histo1[i] histo1 = float(histo1) & chisto1=chisto1/float(chisto1[N-1]+Nsatur1)*100. Nmax = Nmax > MAX(histo1) ENDIF IF KEYWORD_SET(P2) THEN BEGIN histo2 = HISTOGRAM( P2[valid2],min=vmin,max=vmax,bin=box) chisto2 = histo2 & FOR i=2, N-1 DO chisto2[i] = chisto2[i-1]+histo2[i] histo2 = float(histo2) & chisto2=chisto2/float(chisto2[N-1]+Nsatur2)*100. Nmax = Nmax > MAX(histo2) ENDIF val = (vmin + (INDGEN(N)+0.5)*box )*prod.slope+prod.offset xtit = prod.name+' ['+prod.unit+']' IF KEYWORD_SET(NP1) OR KEYWORD_SET(NP2) THEN xtit='['+prod.unit+']' PLOT,val, histo0,XTIT=xtit,YRANGE=[0.,Nmax],POS=[0.1,0.6,0.95,0.99],/NODATA OPLOT,val, histo0,COL=par.wNC+1 IF KEYWORD_SET(P1) THEN OPLOT,val, histo1,COL=par.wNC+2 IF KEYWORD_SET(P2) THEN OPLOT,val, histo2,COL=par.wNC+3 PLOT,val,chisto0,XTIT=xtit,YRANGE=[0.,100.],POS=[0.1,0.1,0.95,0.49],/NODATA,/NOERASE OPLOT,val,chisto0,COL=par.wNC+1,THICK=2 IF KEYWORD_SET(P1) THEN OPLOT,val,chisto1,COL=par.wNC+2,THICK=2 IF KEYWORD_SET(P2) THEN OPLOT,val,chisto2,COL=par.wNC+3,THICK=2 IF KEYWORD_SET(NP1) OR KEYWORD_SET(NP2) THEN BEGIN xpos = 0.05*!X.CRANGE[0]+0.95*!X.CRANGE[1] xyouts,xpos,0.95*!Y.CRANGE[0]+0.05*!Y.CRANGE[1],prod.name,ALIGN=1,COL=par.wNC+1 IF KEYWORD_SET(NP1) THEN $ xyouts,xpos,0.85*!Y.CRANGE[0]+0.15*!Y.CRANGE[1],NP1 ,ALIGN=1,COL=par.wNC+2 IF KEYWORD_SET(NP2) THEN $ xyouts,xpos,0.75*!Y.CRANGE[0]+0.25*!Y.CRANGE[1],NP2 ,ALIGN=1,COL=par.wNC+3 ENDIF END ;================================================================================ PRO Plot_BRDF,params, thes,thev,phi,MULT=mult ; Plot des positions angulaires des donn�es ; MULT indique qu'il y a plusieurs pixels ==> impact sur le choix du symbole ;-------------------------------------------------------------------------------- valid = WHERE(thes GT 0.,count) IF count EQ 0 THEN RETURN thes_cen = MEDIAN(thes[valid]) DEVICE,DECOMPOSE=0 ERASE,params.wNC+4 IF MAX(ABS(thev)) LT 70. THEN themax=70. ELSE themax=90. range = [-themax,themax] ang = INDGEN(361)*!PI/180. plot,range,range,xrange=range,yrange=range,/nodata,pos=[0.0,0.0,1.0,1.0],xstyle=5,ystyle=5 IF themax EQ 70. THEN $ FOR i=20,themax,20 DO oplot,/POLAR,ang*0.+i,ang,col=params.wNC+1 $; Plot les cercles de thetav constant ELSE BEGIN FOR i=30,90,30 DO oplot,/POLAR,ang*0.+i,ang,col=params.wNC+1 ; Plot les cercles de thetav constant FOR i=15,90,30 DO oplot,/POLAR,ang*0.+i,ang,col=params.wNC+1,LINESTYLE=1; Plot les cercles de thetav constant ENDELSE oplot,range,[0.,0.],col=params.wNC+2 ; Plot le plan principal oplot,[0.,0.],range,col=params.wNC+2 ; Plot le plan perpendiculaire ; ; On trace maintenant les iso-angles de phase ; IF params.wactang[2] OR params.wactang[3] THEN BEGIN CT = COS(thes_cen*!DTOR) & ST = SIN(thes_cen*!DTOR) ANG = (INDGEN(2*FIX(themax))+0.5)*!DTOR/2. FOR iphase = 1,7 DO BEGIN phase = iphase*10.*!PI/180. cphi = (cos(phase)-CT*COS(ANG))/(ST*SIN(ANG)) modif = where(cphi LE 1. AND cphi GE -1.) R = [ reverse(ANG[modif]) ,ANG[modif]]*!RADEG azim = [-reverse(ACOS(cphi[modif])),ACOS(cphi[modif])] IF params.wactang[3] THEN azim = !PI-azim oplot,/polar,R,azim,col=params.wNC+3 ENDFOR ENDIF ELSE BEGIN ; Si on ne trace pas les angles de phase, on indique la position du soleil ang = INDGEN(13)/12.*(2.*!PI) CT = COS(ang) OPLOT,thes_cen + 4.*COS(ang), 4.*SIN(ang),col=params.wNC+2 ENDELSE iseq = params.wseq-params.wseqmin IF KEYWORD_SET(mult) THEN BEGIN oplot,/polar,thev[valid],phi[valid]*!DTOR,psym=3,col=0 ; On indique la sequence courante vza = MEDIAN(thev[*,*,iseq]) azi = MEDIAN(phi [*,*,iseq]) oplot,/polar,[vza],[azi*!DTOR],psym=6,col=params.wNC+1 ENDIF ELSE BEGIN oplot,/polar,thev[valid],phi[valid]*!DTOR,PSYM=6,col=0 ; On indique la sequence courante oplot,/polar,[thev[iseq]],[phi[iseq]*!DTOR],PSYM=2,col=params.wNC+1 ENDELSE END ;================================================================================ PRO Plot_signatures,par, prod, thes,thev,phi,P0,P1=P1,P2=P2,MULT=mult,NP1=NP1,NP2=NP2 ; Plot des valeurs ;-------------------------------------------------------------------------------- DEVICE,DECOMPOSE=0 ERASE,par.wNC+4 IF KEYWORD_SET(mult) THEN psym=3 ELSE psym=6 iseq = par.wseq-par.wseqmin valid = WHERE(P0 NE prod.unvalid AND P0 NE prod.satur AND P0 NE prod.dummy AND thev GE 0.,count) IF count EQ 0 THEN RETURN vmin = MIN(P0[valid],MAX=vmax) IF KEYWORD_SET(P1) THEN BEGIN valid1 = WHERE(P1 NE prod.unvalid AND P1 NE prod.satur AND P1 NE prod.dummy,count) IF count NE 0 THEN BEGIN vmin = vmin < MIN(P1[valid1],MAX=vmax1) vmax = vmax > vmax1 ENDIF ENDIF IF KEYWORD_SET(P2) THEN BEGIN valid2 = WHERE(P2 NE prod.unvalid AND P2 NE prod.satur AND P2 NE prod.dummy,count) IF count NE 0 THEN BEGIN vmin = vmin < MIN(P2[valid2],MAX=vmax1) vmax = vmax > vmax1 ENDIF ENDIF vmin = vmin*prod.slope + prod.offset vmax = vmax*prod.slope + prod.offset ytit = prod.name+' ['+prod.unit+']' IF KEYWORD_SET(NP1) OR KEYWORD_SET(NP2) THEN ytit='['+prod.unit+']' IF NOT (par.wactang[2] OR par.wactang[3]) THEN BEGIN ; Trace en fonction de l'angle de vis�e Angle = thev *!RADEG xtit = 'View Angle' ENDIF IF par.wactang[2] THEN BEGIN ; Trace en fonction de l'angle de phase Angle = ACOS(COS(thes)*COS(thev)+SIN(thes)*SIN(thev)*COS(phi))*!RADEG xtit = 'Phase Angle' ENDIF IF par.wactang[3] THEN BEGIN ; Trace en fonction de l'angle d'ecart au glitter Angle = ACOS(COS(thes)*COS(thev)-SIN(thes)*SIN(thev)*COS(phi))*!RADEG xtit = 'Off-Glint Angle' ENDIF ; ; On va s�parer ce qui est a gauche et a droite anglemin = MIN(Angle[valid],imin) IF anglemin LT 30. THEN BEGIN imin = valid[imin] modif = WHERE(thev[valid]*SIN(phi[valid]) LE (thev[imin]*SIN(phi[imin])), count) IF (count GT 1) THEN Angle[valid[modif]] = -Angle[valid[modif]] ENDIF IF KEYWORD_SET(mult) THEN medang = MEDIAN(Angle[*,*,iseq]) ELSE medang = Angle[0,0,iseq] ; ; Plot ; PLOT, Angle[valid],P0[valid]*prod.slope+prod.offset,yrange=[vmin,vmax],XTIT=xtit,YTIT=ytit,COL=0,/NODATA,$ POS=[0.15,0.15,0.97,0.97] OPLOT,[medang,medang],!Y.CRANGE,col=0 ; Repere s�quence courante OPLOT,Angle[valid ],P0[valid ]*prod.slope+prod.offset,PSYM=psym,COL=par.wNC+1 IF KEYWORD_SET(P1) THEN OPLOT,Angle[valid1],P1[valid1]*prod.slope+prod.offset,PSYM=psym,COL=par.wNC+2 IF KEYWORD_SET(P2) THEN OPLOT,Angle[valid2],P2[valid2]*prod.slope+prod.offset,PSYM=psym,COL=par.wNC+3 IF KEYWORD_SET(NP1) OR KEYWORD_SET(NP2) THEN BEGIN xpos = 0.05*!X.CRANGE[0]+0.95*!X.CRANGE[1] xyouts,xpos,0.95*!Y.CRANGE[0]+0.05*!Y.CRANGE[1],prod.name,ALIGN=1,COL=par.wNC+1 IF KEYWORD_SET(NP1) THEN $ xyouts,xpos,0.85*!Y.CRANGE[0]+0.15*!Y.CRANGE[1],NP1 ,ALIGN=1,COL=par.wNC+2 IF KEYWORD_SET(NP2) THEN $ xyouts,xpos,0.75*!Y.CRANGE[0]+0.25*!Y.CRANGE[1],NP2 ,ALIGN=1,COL=par.wNC+3 ENDIF END ;================================================================================ PRO Plot_signatures_aerosol,par, thes,thev,phi,Ref490, Ref670, Ref865, Ref490M ,Ref670M, Ref865M, $ RefP490,RefP670,RefP865,RefP490M,RefP670M,RefP865M ; Plot des signatures aerosols. Adapt� � la lecture du fichier de suivi ;-------------------------------------------------------------------------------- DEVICE,DECOMPOSE=0 WINDOW,6,XSIZE=300,YSIZE=200,XPOS=par.tlb_size[0]+200+2*par.inter,YPOS=200+2*par.inter,TIT='Aerosol Reflectance Signatures' ERASE,par.wNC+4 slope = 1.E-2 offset = -100. valid = WHERE(Ref670 LT 20000. AND thev GE 0.,count) IF count EQ 0 THEN RETURN Ref490 = Ref490 [valid] Ref670 = Ref670 [valid] Ref865 = Ref865 [valid] Ref490M = Ref490M[valid] Ref670M = Ref670M[valid] Ref865M = Ref865M[valid] RefP490 = RefP490[valid] RefP670 = RefP670[valid] RefP865 = RefP865[valid] RefP490M=RefP490M[valid] RefP670M=RefP670M[valid] RefP865M=RefP865M[valid] vmax = MAX([Ref490, Ref670 ,Ref865 ,Ref670M ,Ref865M ])*slope+offset vmin = MIN([Ref490, RefP670,RefP865,RefP670M,RefP865M])*slope+offset Angle = 180.-ACOS(COS(thes)*COS(thev)+SIN(thes)*SIN(thev)*COS(phi))*!RADEG xtit = 'Scattering Angle' ; Par defaut, on trace en fonction de l'angle de diffusion. Autres choix possibles : IF par.wactang[0] THEN BEGIN ; Trace en fonction de l'angle de vis�e Angle = thev *!RADEG xtit = 'View Angle' ENDIF IF par.wactang[2] THEN BEGIN ; Trace en fonction de l'angle de phase Angle = ACOS(COS(thes)*COS(thev)+SIN(thes)*SIN(thev)*COS(phi))*!RADEG xtit = 'Phase Angle' ENDIF IF par.wactang[3] THEN BEGIN ; Trace en fonction de l'angle d'ecart au glitter Angle = ACOS(COS(thes)*COS(thev)-SIN(thes)*SIN(thev)*COS(phi))*!RADEG xtit = 'Off-Glint Angle' ENDIF Angle = Angle[valid] IF (par.wactang[0] OR par.wactang[2] OR par.wactang[3] ) THEN BEGIN ; On va separer ce qui est a gauche et a droite anglemin = MIN(Angle,imin) IF anglemin LT 30. THEN BEGIN modif = WHERE(thev[valid]*SIN(phi[valid]) LE (thev[imin]*SIN(phi[imin])), count) IF (count GT 1) THEN Angle[modif] = -Angle[modif] ENDIF ENDIF Ytit = 'Reflectance [%]' ; ; Plot ; PLOT, Angle,Ref670*slope,yrange=[vmin,vmax],XTIT=xtit,YTIT=ytit,COL=0,/NODATA,$ POS=[0.12,0.14,0.99,0.99] OPLOT,Angle, Ref490 *slope+offset, COL=par.wNC+3, PSYM= 4 OPLOT,Angle, Ref670 *slope+offset, COL=par.wNC+2, PSYM= 4 OPLOT,Angle, Ref865 *slope+offset, COL=par.wNC+1, PSYM= 4 OPLOT,Angle, Ref490M*slope+offset, COL=par.wNC+3;, PSYM=-7 OPLOT,Angle, Ref670M*slope+offset, COL=par.wNC+2;, PSYM=-7 OPLOT,Angle, Ref865M*slope+offset, COL=par.wNC+1;, PSYM=-7 OPLOT,Angle, RefP490 *slope+offset, COL=par.wNC+3, PSYM= 6 OPLOT,Angle, RefP670 *slope+offset, COL=par.wNC+2, PSYM= 6 OPLOT,Angle, RefP865 *slope+offset, COL=par.wNC+1, PSYM= 6 OPLOT,Angle, RefP490M*slope+offset, COL=par.wNC+3, LINESTYLE=2;, PSYM=-7 OPLOT,Angle, RefP670M*slope+offset, COL=par.wNC+2, LINESTYLE=2;, PSYM=-7 OPLOT,Angle, RefP865M*slope+offset, COL=par.wNC+1, LINESTYLE=2;, PSYM=-7 END ;================================================================================ PRO Plot_signatures_aerosol_terre,par, thes,thev,phi,RefSurf,Ref490, Ref670, Ref865, Ref490M ,Ref670M, Ref865M ; Plot des signatures aerosols. Adapte a la lecture du fichier de suivi ;-------------------------------------------------------------------------------- DEVICE,DECOMPOSE=0 WINDOW,6,XSIZE=500,YSIZE=300,XPOS=par.tlb_size[0]+200+2*par.inter,YPOS=200+2*par.inter,TIT='Aerosol Reflectance Signatures' ERASE,par.wNC+4 ;slope = 1.E-1 ;offset = 0. slope = 1.E-2 offset = -100. valid = WHERE(RefSurf LT 20000. AND Ref490 LT 20000. AND Ref670 LT 20000. AND Ref865 LT 20000. AND $ Ref490M LT 20000. AND Ref670M LT 20000. AND Ref865M LT 20000. AND thev GE 0. ,count) IF count EQ 0 THEN RETURN RefSurf = RefSurf[valid] Ref490 = Ref490 [valid] Ref670 = Ref670 [valid] Ref865 = Ref865 [valid] Ref490M = Ref490M[valid] Ref670M = Ref670M[valid] Ref865M = Ref865M[valid] vmax = MAX([RefSurf,Ref490, Ref670 ,Ref865 ,Ref490M, Ref670M ,Ref865M ])*slope+offset vmin = MIN([RefSurf,Ref490, Ref670 ,Ref865 ,Ref490M, Ref670M ,Ref865M ])*slope+offset Angle = 180.-ACOS(COS(thes)*COS(thev)+SIN(thes)*SIN(thev)*COS(phi))*!RADEG xtit = 'Scattering Angle' ; Par defaut, on trace en fonction de l'angle de diffusion. Autres choix possibles : IF par.wactang[0] THEN BEGIN ; Trace en fonction de l'angle de visee Angle = thev *!RADEG xtit = 'View Angle' ENDIF IF par.wactang[2] THEN BEGIN ; Trace en fonction de l'angle de phase Angle = ACOS(COS(thes)*COS(thev)+SIN(thes)*SIN(thev)*COS(phi))*!RADEG xtit = 'Phase Angle' ENDIF IF par.wactang[3] THEN BEGIN ; Trace en fonction de l'angle d'ecart au glitter Angle = ACOS(COS(thes)*COS(thev)-SIN(thes)*SIN(thev)*COS(phi))*!RADEG xtit = 'Off-Glint Angle' ENDIF Angle = Angle[valid] IF (par.wactang[0] OR par.wactang[2] OR par.wactang[3] ) THEN BEGIN ; On va separer ce qui est a gauche et a droite anglemin = MIN(Angle,imin) IF anglemin LT 30. THEN BEGIN modif = WHERE(thev[valid]*SIN(phi[valid]) LE (thev[imin]*SIN(phi[imin])), count) IF (count GT 1) THEN Angle[modif] = -Angle[modif] ENDIF ENDIF Ytit = 'Polarized Ref [%]' ; ; Plot ; PLOT, Angle,Ref670*slope,yrange=[vmin,vmax],XTIT=xtit,YTIT=ytit,COL=0,/NODATA,$ POS=[0.12,0.14,0.99,0.99] OPLOT,Angle, RefSurf*slope+offset OPLOT,Angle, Ref490 *slope+offset, COL=par.wNC+3, PSYM= 4 OPLOT,Angle, Ref670 *slope+offset, COL=par.wNC+2, PSYM= 4 OPLOT,Angle, Ref865 *slope+offset, COL=par.wNC+1, PSYM= 4 OPLOT,Angle, Ref490M*slope+offset, COL=par.wNC+3;, PSYM=-7 OPLOT,Angle, Ref670M*slope+offset, COL=par.wNC+2;, PSYM=-7 OPLOT,Angle, Ref865M*slope+offset, COL=par.wNC+1;, PSYM=-7 END ;================================================================================ FUNCTION line,val,param,NOUNIT=nounit ; Permet un affichage des valeurs en tenant compte des valeurs saturees et Dummy ;-------------------------------------------------------------------------------- islope = FLOOR(ALOG10(param.slope)) IF KEYWORD_SET(nounit) THEN BEGIN IF val EQ param.dummy OR val EQ param.unvalid OR val EQ param.satur THEN CASE islope OF -4 : RETURN, ' -9.9999' -4 : RETURN, ' -9.999' -4 : RETURN, ' -9.99' -4 : RETURN, ' -99.9' ELSE: RETURN, ' -999' END CASE islope OF -4 : RETURN, STRING(val*param.slope + param.offset,format='(F8.4)') -3 : RETURN, STRING(val*param.slope + param.offset,format='(F8.3)') -2 : RETURN, STRING(val*param.slope + param.offset,format='(F8.2)') -1 : RETURN, STRING(val*param.slope + param.offset,format='(F8.1)') ELSE: RETURN, STRING(val*param.slope + param.offset,format='( I8)') END ENDIF ELSE BEGIN CASE islope OF -4 : fmt = '(A14," :",F7.4," ",A6)' -3 : fmt = '(A14," :",F7.3," ",A6)' -2 : fmt = '(A14," :",F7.2," ",A6)' -1 : fmt = '(A14," :",F7.1," ",A6)' ELSE: fmt = '(A14," :", I7," ",A6)' END IF val EQ param.dummy THEN RETURN, STRING(param.name,format=fmt)+' Dummy' IF val EQ param.unvalid THEN RETURN, STRING(param.name,format=fmt)+' Unvalid' IF val EQ param.satur THEN RETURN, STRING(param.name,format=fmt)+' Saturated' val2 = val*param.slope + param.offset RETURN, STRING(param.name,val2,param.unit,format=fmt) ENDELSE END ;================================================================================ PRO display_ctbl, pstate ; Display de la palette de couleur ;-------------------------------------------------------------------------------- par = *(*pstate).wstrParam WSET,par.wpid DEVICE,DECOMPOSE=0 ERASE ; On fabrique le tableau pour repr�senter la palette de couleur (V) pos=[0.05,0.55,0.95,1.] pxsize = LONG((POS[2]-POS[0])*!D.X_SIZE + 0.5) pysize = LONG((POS[3]-POS[1])*!D.Y_SIZE + 0.5) V = BYTARR(pxsize,pysize) Vv = BYTE(INDGEN(pxsize)*(par.wNC-1.)/float(pxsize-1))+1 FOR i=0,pysize-1 DO V[*,i] = Vv TV,V,pos[0],pos[1],/NORMAL ; On ajoute les valeurs plot,[0.,1.],[0.,1.],xrange=[par.wvmin,par.wvmax],pos=pos,/NODATA,/NORMAL,$ XSTYLE=1,YSTYLE=4,/NOERASE ; ; On ajoute les unit�s sur la palette de couleur type = par.wchan/100 p = par.wchan MOD 100 prod = *(*pstate).wstrProd CASE type OF 0 : unit = (prod.U_par[p]).unit 1 : unit = (prod.D_par[p]).unit 2 : unit = (prod.U_par[(prod.C_par[p] ).p1]).unit 3 : unit = (prod.D_par[(prod.Cd_par[p]).p1]).unit ENDCASE xyouts,0.99,0.05,ALIGN=1,unit,/NORMAL xyouts,0.01,0.05,ALIGN=0,unit,/NORMAL END ;================================================================================ PRO display, pstate ; Visualisation du champ choisi, et ajout des lignes correspondant aux angles et a la carte ;-------------------------------------------------------------------------------- par = *(*pstate).wstrParam iseq = par.wseq-par.wseqmin cha_typ = par.wchan/100 ptrvisu = (*(*pstate).wstrTab).wvvisu WSET,par.wid CASE cha_typ OF 0 : BEGIN ; 1 canal Non directionnel DEVICE,DECOMPOSE=0 ERASE,par.wNC+4 TV,REBIN((*ptrvisu),par.wfz*par.wnbc,par.wfz*par.wnbl,/SAMPLE),par.wMapPos[0],par.wMapPos[1],/DEVICE END 1 : BEGIN ; 1 canal directionnel DEVICE,DECOMPOSE=0 ERASE,par.wNC+4 TV,REBIN((*ptrvisu)[*,*,iseq],par.wfz*par.wnbc,par.wfz*par.wnbl,/SAMPLE),par.wMapPos[0],par.wMapPos[1],/DEVICE END 2 : BEGIN ; 3 canaux, Non directionnel DEVICE,DECOMPOSE=1 ERASE,!D.N_COLORS-1 TV,REBIN((*ptrvisu),par.wfz*par.wnbc,par.wfz*par.wnbl,3,/SAMPLE),par.wMapPos[0],par.wMapPos[1],/DEVICE ,TRUE=3 END 3 : BEGIN ; 3 canaux, directionnel DEVICE,DECOMPOSE=1 ERASE,!D.N_COLORS-1 TV,REBIN(REFORM((*ptrvisu)[*,*,iseq,*],par.wnbc,par.wnbl,3),$ par.wfz*par.wnbc,par.wfz*par.wnbl,3,/SAMPLE),par.wMapPos[0],par.wMapPos[1],TRUE=3,/DEVICE END ENDCASE ; ; On ajoute les angles (Niveau 1 seulement) ; IF STRMID((*(*pstate).wStrProd).type,1,1) EQ '1' AND (cha_typ EQ 1 OR cha_typ EQ 3) THEN BEGIN colors = [1,2,3,3] + par.wNC DEVICE,DECOMPOSE=0 ; On definit le systeme de coordonnes pour le trace PLOT,[0.,par.wnbc-1.],[0.,par.wnbl-1],xrange=[0.,par.wnbc-1.],yrange=[0.,par.wnbl-1],xstyle=5,ystyle=5,/NOERASE,$ POSITION = par.wMapPos,/DEVICE,/NODATA ; Boucle sur les 4 angles FOR iang = 0,3 DO IF (par.wactang)[iang] THEN BEGIN ; On recupere la structure qui donne les infos strang = *(*(*(*(*pstate).wStrTab).wangstr))[iang,iseq] ; Trac� des segments FOR iseg = 0, strang.Nvert-1 DO IF (strang.beg[iseg+1]-strang.beg[iseg]) GT 1 THEN $ OPLOT,strang.X[strang.beg[iseg]:strang.beg[iseg+1]-1],$ strang.Y[strang.beg[iseg]:strang.beg[iseg+1]-1],COL=colors[iang] ENDIF ENDIF IF (par.wactMap)[0] THEN overlay_map,pstate END ;================================================================================ PRO overlay_map, pstate ; Ajout d'une carte sur la zone de trac� ;-------------------------------------------------------------------------------- par = (*pstate).wstrParam latmax = (*par).wMapLatC + 0.5 * (*par).wMapSizeNS*9.E-3 / ((*par).wMapPos[3]-(*par).wMapPos[1]) * (*par).wdys latmin = (*par).wMapLatC - 0.5 * (*par).wMapSizeNS*9.E-3 / ((*par).wMapPos[3]-(*par).wMapPos[1]) * (*par).wdys delta_lat = latmax-latmin IF latmax*latmin LE 0. THEN MinAbsLon = 0. ELSE $ MinAbsLon = MIN(ABS([latmin,latmax])) delta_lon = delta_lat * (*par).wdxs/float((*par).wdys) /COS(MinAbsLon*!DTOR) ; ; On traite les cas tordus ou lat depassent les poles pos = [0.,0.,1.,1.] IF latmax GT 90. THEN BEGIN pos[3] = 0.5 + ( 90.-(*par).wMapLatC)/(latmax-(*par).wMapLatC)/2. latmax = 90. ENDIF IF latmin LT -90. THEN BEGIN pos[1] = 0.5 - (-90.-(*par).wMapLatC)/(latmin-(*par).wMapLatC)/2. latmin = -90. ENDIF IF delta_lon GT 360. THEN BEGIN pos[0] = 0.5 - 180./delta_lon pos[2] = 0.5 + 180./delta_lon ENDIF ; ; On peut alors tracer la carte En vert ou Noir suivant la palette utilis�e WIDGET_CONTROL, (*(*pstate).wstrWidg).wcolBG,GET_VALUE=c IF c EQ 0 THEN col=(*par).wNC+2 ELSE col = 0 col = 2 MAP_SET,0.,(*par).wMapLonC,/NOBORDER,/GRID,/LABEL, $ LIMIT=[latmin,(*par).wMapLonC-delta_lon/2.,latmax,(*par).wMapLonC+delta_lon/2.], $ POSITION=pos,/SINUSOIDAL,/NOERASE IF ((*par).wactMap)[1] THEN MAP_CONTINENTS,/COASTS,/COUNTRIES,COL=col,/HIRES $ ELSE MAP_CONTINENTS,/COASTS,/COUNTRIES,COL=col END ;======================================================== ; This function returns the directory separator, as a function of the OS system being used FUNCTION path_sep ;------------------------------------------------------------------------------------------ CASE !VERSION.OS_FAMILY OF 'MacOS' : sep=':' 'unix' : sep='/' 'Windows' : sep='\' ENDCASE RETURN,sep END ;======================================================== FUNCTION make_browse,path,latmin,latmax,loncen,RapSize,NlinMax,RMAX=rmax,PARASOL=parasol ; Cette fonction g�n�re une image "Browse" a partir d'un fichier de ; niveau 1, et de coordonn�es g�ographiques. Le fichier est ; echantillon� en fonction de la r�solution demand�e ; INPUT : path : Chemin pour le fichier de niveau 1 (sans "D", ni "L") ; latmin : Latitude minimum a considerer ; latmax : latitude maximale a considerer ; loncen : Longitude centrale de la projection ; RapSize : Rapport entre taille WE et NS a considerer ; Nlinmax : Nombre maximum de lignes en sortie. En pratique, ca ; peut etre moins car on fait un �chantillonage "entier" ; OPTION : RMAX : Reflectance maximale a considerer ; SORTIE : La fonction retourne un pointeur vers une structure qui donne toutes les infos ; sur le browse. ; .latmin ; .latmax ; .loncen ; .fz Pas d'�chantillonage (entier) ; .Rmax Valeur maximale de reflectance utilis�e ; .tab tableau BYTARR(3,Ncol,Nlin) qui peut etre directement visualis� ; sur les "true color display" ;------------------------------------------------------------------------------------------ Conv = 1.5E-3*!DTOR IF NOT KEYWORD_SET(Rmax) THEN Rmax = 0.4 ; On recupere le nombre de pixels par ligne Nlin = 3240 & Npix=INTARR(Nlin) & NpixSum = LONARR(Nlin) fileL = path & Dpos = STRPOS(fileL,'D',/REVERSE_SEARCH) & STRPUT,fileL,'L',Dpos openr,lun,fileL,/get_Lun point_lun,lun,180+360+1620+180+166320+720+13140+204 readf,lun,Npix,format='(3240I4)' free_lun,lun IF parasol NE 0 THEN BEGIN NpixSum[Nlin-1] = 0 FOR i = Nlin-2, 0, -1 DO NpixSum[i] = NpixSum[i+1]+ Npix[i+1] NumbDir = 16 IF parasol EQ 2 THEN NumbDir = 26 ENDIF ELSE BEGIN NpixSum[0] = 0 FOR i = 1, Nlin-1 DO NpixSum[i] = NpixSum[i-1]+ Npix[i-1] NumbDir = 14 ENDELSE posNseq = 15 + NumbDir*2 SnonDir = 18 + NumbDir*2 rec_size = 18 + NumbDir*45 ; ; On d�termine la taille de la fenetre ; NlinPol = FIX((latmax-latmin)*18) NcolPol = FIX((latmax-latmin)*18*RapSize) fz = (MAX([NlinPol,NcolPol])-1)/NlinMax + 1 Nlin = NlinPol/fz Ncol = NcolPol/fz ; ; Ouverture du fichier de donnees ; OPENR,lun,path,/get_Lun,ERROR=err browse = BYTARR(Ncol,Nlin,3) linmax = FIX( 18.*(90.-latmin)-0.5*fz ) FOR ilin = 0, Nlin-1 DO BEGIN linpol = linmax - ilin*fz ; ; Lectude d'une ligne de donn�es ; point_lun,lun,180+NpixSum[linpol]*rec_size IF Npix[linpol] EQ 0 THEN GOTO, nextline data = bytarr(rec_size, Npix[linpol]) readu,lun,data NonDir = data[ 0: Snondir-1,*] col = REFORM(NonDir[ 8,*]*256 + NonDir[ 9,*]) lat = 90. - (linpol+0.5)/18. NcolM = 2*ROUND(3240.*COS(lat*!DTOR)) colcen = FIX(((loncen+180.) MOD 360.)/360.*NcolM) ; colcen va de 0 a Ncol-1 entre -180 et 180. colcor = (col-3241+NcolM/2) MOD NcolM ; colcor va de 0 a Ncol-1 entre -180 et 180. dist = ((colcor-colcen + NcolM/2) MOD NcolM)-NcolM/2 IF (Ncol MOD 2) EQ 0 THEN $ valid = WHERE( (ABS(dist) LE fz*(Ncol/2)) AND ( ((dist+fz/2 ) MOD fz) EQ 0), count) $ ELSE valid = WHERE( (ABS(dist) LE fz*(Ncol/2)) AND ( ((dist ) MOD fz) EQ 0), count) IF count NE 0 THEN BEGIN indice = FIX(dist[valid]/float(fz) + Ncol/2.) ; Les 3 lignes ci dessus ont �t� v�rifi�es Nseq = REFORM(NonDir[posNseq,valid]) ; Nombre de sequences valides Dir = REFORM(data[SnonDir:rec_size-1,valid],43,NumbDir,count) ; On recupere les infos directionelles ext = BYTARR(43,count) & FOR i=0,count-1 DO ext[*,i]= Dir[*,Nseq[i]/2,i]; On prend la sequence centrale fac = 1.E-4/COS((ext[ 5,*]*256l + ext[ 6,*])*Conv)*255./Rmax ; Passage en reflectance et normalisatio browse[indice,ilin,2] = BYTE( (((ext[15,*]*256s + ext[16,*])*fac) <255 ) >0 ) browse[indice,ilin,1] = BYTE( (((ext[21,*]*256s + ext[22,*])*fac) <255 ) >0 ) browse[indice,ilin,0] = BYTE( (((ext[27,*]*256s + ext[28,*])*fac) <255 ) >0 ) ENDIF nextline: ENDFOR free_lun,lun ; struc = {latmin:latmin,latmax:latmax,loncen:loncen,fz:fz,Rmax:Rmax,tab:browse} RETURN,PTR_NEW(struc) END ;������������������������������������������������������������������������� ; PROCEDURE PRINCIPALE : CREATION DE WIDGETS ET GESTION DE LEUR HIERARCHIE ;������������������������������������������������������������������������� PRO AnaPol IF !VERSION.OS_FAMILY EQ 'unix' THEN DEVICE,RETAIN=2 ELSE DEVICE,RETAIN=1 IF !VERSION.OS_FAMILY NE 'Windows' THEN DEVICE, TRUE=24 ; ��� CREATION DE l'ENVIRONNEMENT BASES ET WIDGETS ��� ; Creation de la TopLevelBase ; =========================== TopLevelBase=WIDGET_BASE(TITLE='ANAPOL',MBAR=MenuBar) ; Creation de la sous-base SelectionBase ; ====================================== SelectionBase=WIDGET_BASE(TopLevelBase,/COLUMN) ; Creation des menus ; ================== FileMenu=WIDGET_BUTTON(MenuBar,VALUE='File',/MENU,EVENT_PRO='FileMenu_Event') HelpMenu=WIDGET_BUTTON(MenuBar,VALUE='Help',/MENU,EVENT_PRO='HelpMenu_Event') ; Creation des options de chaque menu ; =================================== SaveOption =WIDGET_BUTTON(FileMenu ,VALUE='Image Save' ,UVALUE='save',/MENU) SaveView =WIDGET_BUTTON(SaveOption,VALUE='Polder View' ,UVALUE='save_view') SaveAng =WIDGET_BUTTON(SaveOption,VALUE='Polar Diagram' ,UVALUE='save_ang') SaveRef =WIDGET_BUTTON(SaveOption,VALUE='Reflectance Plot',UVALUE='save_ref') TXT_Option =WIDGET_BUTTON(FileMenu ,VALUE='Text_Save' ,UVALUE='Text_Save') HDF_Option =WIDGET_BUTTON(FileMenu ,VALUE='HDF_Save' ,UVALUE='HDF_Save') ExitOption =WIDGET_BUTTON(FileMenu ,VALUE='Exit' ,UVALUE='exit') ShortlOption=WIDGET_BUTTON(HelpMenu ,VALUE='Short' ,UVALUE='short') ; Creation de la sous-base OrbitBase ; ================================== OrbitBase=WIDGET_BASE(SelectionBase,/COLUMN,FRAME=2,EVENT_PRO='OrbitSelect_Event') ; Creation du widget de selection d'orbite ; ======================================== OrbitButton=WIDGET_BUTTON(OrbitBase,XSIZE=150,VALUE='POLDER Product',UVALUE='orbit') OrbitLabel=WIDGET_LABEL(OrbitBase,VALUE='Selected File',UVALUE='label',/DYNAMIC_RESIZE) ; Creation de la sous-base AreaBase ; ================================= AreaBase=WIDGET_BASE(SelectionBase,/COLUMN,FRAME=2,EVENT_PRO='AreaSelect_Event') ; Creation des widgets de selection de region ; =========================================== lat_cent=46. & lon_cent=5. & sizeWE=1000. & sizeNS=1000. LonCentField=CW_FIELD(AreaBase,VALUE=lon_cent,/FLOATING,UVALUE='loncent', $ XSIZE=7,TITLE='LON CENT',/RETURN_EVENTS) LatCentField=CW_FIELD(AreaBase,VALUE=lat_cent,/FLOATING,UVALUE='latcent', $ XSIZE=7,TITLE='LAT CENT',/RETURN_EVENTS) NbLinField =CW_FIELD(AreaBase,VALUE=ROUND(sizeNS),/LONG,UVALUE='sizeNS', $ XSIZE=5,TITLE='N-S [km]',/RETURN_EVENTS) NbColField =CW_FIELD(AreaBase,VALUE=ROUND(sizeWE),/LONG,UVALUE='sizeWE', $ XSIZE=5,TITLE='W-E [km]',/RETURN_EVENTS) cm0 = WIDGET_BASE(AreaBase,/ROW) & cm1 = WIDGET_BASE(cm0,/COLUMN) & cm2 = WIDGET_BASE(cm0,/COLUMN) OrbitMapButton=WIDGET_BUTTON(cm1,XSIZE=70,VALUE='ORBIT MAP',UVALUE='orbitmap',SENSITIVE=0) BrowseButton =WIDGET_BUTTON(cm1,XSIZE=70,VALUE='BROWSE' ,UVALUE='browse' ,SENSITIVE=0) ZoomButton =WIDGET_BUTTON(cm2,XSIZE=70,VALUE='ZOOM' ,UVALUE='zoom' ,SENSITIVE=0) ReadDataButton=WIDGET_BUTTON(cm2,XSIZE=70,VALUE='READ DATA',UVALUE='readata' ,SENSITIVE=0, $ EVENT_PRO='ReadData_Event') WIDGET_CONTROL,LatCentField,SENSITIVE=0 WIDGET_CONTROL,LonCentField,SENSITIVE=0 WIDGET_CONTROL,NbLinField,SENSITIVE=0 WIDGET_CONTROL,NbColField,SENSITIVE=0 ; ; Creation du widget de selection de canal ; ======================================== ChannelDrop=WIDGET_DROPLIST(SelectionBase,VALUE=['To be selected'],UVALUE='channel', $ TITLE='Parameter',EVENT_PRO='Visu_Event') WIDGET_CONTROL,ChannelDrop,SENSITIVE=0 ; ; Creation de la sous-base SequenceBase (Choix des affichages des sequences) ; ========================================================================== SequenceBase=WIDGET_BASE(SelectionBase,/COLUMN,FRAME=2,EVENT_PRO='Visu_Event') ; Creation du widget de selection de sequence SequenceSlider=WIDGET_SLIDER(SequenceBase,VALUE=0,UVALUE='sequence', $ MINIMUM=0,MAXIMUM=20, TITLE='SEQUENCE') WIDGET_CONTROL,SequenceSlider,SENSITIVE=0 SequenceButton=WIDGET_BUTTON(SequenceBase,XSIZE=150,VALUE='LOOP',UVALUE='loop', $ EVENT_PRO='Visu_Event',SENSITIVE=0) ; ; Creation de la sous-base AngleBase (Choix des affichages des angles) ; ==================================================================== AngleBase=WIDGET_BASE(SelectionBase,/COLUMN,FRAME=2,EVENT_PRO='Visu_Event') ; Creation du widget de selection d'angles AngleChoice=['VZA','AZI','SCAT','GLIT'] & active_ang=[0b,0b,0b,0b] AngleBGroup=CW_BGROUP(AngleBase,AngleChoice,BUTTON_UVALUE=['vza','azi','scat','glit'], $ SET_VALUE=active_ang,UVALUE='angles',/NONEXCLUSIVE,COLUMN=2) WIDGET_CONTROL,AngleBGroup,SENSITIVE=0 ; ; Creation de la sous-base Map (Choix des affichages des angles) ; ==================================================================== MapBase=WIDGET_BASE(SelectionBase,/COLUMN,FRAME=2,EVENT_PRO='Visu_Event') active_Map=[1b,0b] MapGroup=CW_BGROUP(MapBase,['Map','Hi-Res'],BUTTON_UVALUE=['map','hires'],ROW=1, $ UVALUE='map',SET_VALUE=active_Map,/NONEXCLUSIVE) WIDGET_CONTROL,MapGroup,SENSITIVE=0 ; Creation de la sous-base RangeBase (Choix du min/max de la palette de couleur) ; ============================================================================== RangeBase=WIDGET_BASE(SelectionBase,/COLUMN,FRAME=2,EVENT_PRO='Visu_Event') ;creation des widgets de selection de bornes MinField=CW_FIELD(RangeBase,VALUE=0.,/FLOATING,UVALUE='min', $ XSIZE=8,TITLE='MIN',/RETURN_EVENTS) MaxField=CW_FIELD(RangeBase,VALUE=0.3,/FLOATING,UVALUE='max', $ XSIZE=8,TITLE='MAX',/RETURN_EVENTS) AutoButton=CW_BGROUP(RangeBase,['User','Auto'],BUTTON_UVALUE=['User','Auto'], $ UVALUE='auto',/EXCLUSIVE,COLUMN=2,SET_VALUE=1b,/NO_RELEASE) WIDGET_CONTROL,MinField,SENSITIVE=0 WIDGET_CONTROL,MaxField,SENSITIVE=0 ; Creation de la partie "trac�s" ; ==================================================== visubase = WIDGET_BASE(TopLevelBase,/COLUMN,XOFFSET=180,YOFFSET=0) ; Creation de la widget draw (Fenetre de visualisation) ; ==================================================== draw_xsize=500 draw_ysize=500 Draw=WIDGET_DRAW(visubase,XSIZE=draw_xsize,YSIZE=draw_ysize,$ EVENT_PRO='Fenetre_Event',/BUTTON_EVENTS,UVALUE='draw') WIDGET_CONTROL,Draw,SENSITIVE=0 ; Creation des widgets de controle de la palette ; ==================================================== pal = WIDGET_BASE(visubase,/ROW,EVENT_PRO='Visu_Event') ColGroup=CW_BGROUP(pal,['Grey','Rainbow'],BUTTON_UVALUE=['grey','rainbow'], $ UVALUE='ctbl',/EXCLUSIVE,COLUMN=1,SET_VALUE=0b,/NO_RELEASE) WIDGET_CONTROL,ColGroup,SENSITIVE=0 DispPal=WIDGET_DRAW(pal,XSIZE=draw_xsize-130,YSIZE=50,SENSITIVE=0) ; ��� CONTROLE SUR LES WIDGETS ��� ;on realise la TopLevelBase interv = 30 WIDGET_CONTROL, TopLevelBase,/REALIZE,TLB_SET_Xoffset=interv,TLB_SET_Yoffset=interv,tlb_get_size=tlb_size tlb_size = tlb_size + interv ; On recupere les valeurs d'initialisation affectees aux widgets WIDGET_CONTROL,Draw,GET_VALUE=draw_id WIDGET_CONTROL,DispPal,GET_VALUE=Pal_id WIDGET_CONTROL,AngleBGroup,GET_VALUE=active_ang WIDGET_CONTROL,MinField,GET_VALUE=vmin WIDGET_CONTROL,MaxField,GET_VALUE=vmax ; ; ��� PASSAGE PAR STRUCTURE ��� NbCol = 245 < (!D.N_COLORS-5) tab=FLTARR(10) tabptr = PTRARR(4,10) stru = {tempo:0} ; Lorsqu'on passe par structure un widget complet c'est pour pouvoir modifier ; sa valeur dans une procedure evenementielle. struct_widgets={wOrbL:OrbitLabel, $ wLonCenF:LonCentField,wLatCenF:LatCentField, $ wNbLinF:NbLinField,wNbColF:NbColField, $ wReadDataB:ReadDataButton,wOrbMapB:OrbitMapButton,$ wBrowseB:BrowseButton, wZoomB:ZoomButton, $ wSeqS:SequenceSlider, wSeqB:SequenceButton,$ wChanD:ChannelDrop, wAngleBG:AngleBGroup, wMapBG:MapGroup,$ wMinF:MinField, wMaxF:MaxField, wAutoB:AutoButton, $ wDraw:draw,wcolBG:ColGroup,wPal:DispPal} struct_tableaux={wUtab:PTRARR(99), wDtab:PTRARR(99), $ wLin:PTR_NEW(tab,/NO_COPY), wCol:PTR_NEW(tab,/NO_COPY), wDQX:PTR_NEW(tab,/NO_COPY), $ wSZA:PTR_NEW(tab,/NO_COPY), wVZA:PTR_NEW(tab,/NO_COPY),wAZI:PTR_NEW(tab,/NO_COPY), $ wAngStr:PTR_NEW(tabptr,/NO_COPY),wvvisu:PTR_NEW(tab,/NO_COPY)} struct_parametres={wpathHelp:'Help_AnaPol.txt', wfilein:'', wpathin:'', wpathout:'', wloneq:0., parasol:0b, $ pNpix: PTR_NEW(tab), wlatc:0., wlonc:0. , wsizeNS:0., wsizeWE:0., wZpos:[0.,0.,1.,1.], $ wMapLatC:lat_cent, wMapLonC:lon_cent, wMapSizeNS:sizeNS, wMapSizeWE:sizeWE, wfz:0, wMapPos:[0.,0.,1.,1.], $ wsamp:0,wchan:0, wactang:active_ang, wactmap:active_Map, wnbl:0l, wnbc:0l, $ wNC:NbCol, wvmin:vmin, wvmax:vmax, wauto:1b, $ wseqmin:0, wseqmax:20, wseq:10, $ wdxs:draw_xsize, wdys:draw_ysize, wid:draw_id, wpid:Pal_id, wvdisp:0l, tlb_size:tlb_size,inter:interv,$ ptrbrowse: PTR_NEW(stru)} state={wstrWidg :PTR_NEW(struct_widgets ,/NO_COPY), $ ; Pointeur sur une structure definissant les widgets wstrTab :PTR_NEW(struct_tableaux ,/NO_COPY), $ ; Pointeur sur une structure qui regroupe les tableaux de donn�es wstrParam:PTR_NEW(struct_parametres,/NO_COPY), $ ; Pointeur sur une structure contenant les parametres variables wstrProd :PTR_NEW(stru) } ; Pointeur sur une structure definissant le produit pstate=PTR_NEW(state, /NO_COPY) WIDGET_CONTROL,TopLevelBase,SET_UVALUE=pstate ; ; Appel de la palette de couleur, et initialisation des fenetres de visualisation ; make_palette, NbCol, 0 DEVICE, DECOMPOSE=0 WSET, Pal_id ERASE WSET,Draw_id ERASE xyouts,0.5,0.9,'ANAPOL' ,ALIGN=0.5,/NORMAL,CHARSIZE=2.5,COL=NbCol+1 xyouts,0.5,0.8,'POLDER data visualisation and Analysis' ,ALIGN=0.5,/NORMAL,CHARSIZE=2. ,COL=NbCol+1 xyouts,0.5,0.6,'Francois-Marie Breon' ,ALIGN=0.5,/NORMAL,CHARSIZE=2. ,COL=NbCol+3 xyouts,0.5,0.5,'Laboratoire des Sciences du Climat et de l Environnement',ALIGN=0.5,/NORMAL,CHARSIZE=1.5,COL=NbCol+3 xyouts,0.5,0.2,'Comments, questions, bug report: fmbreon@cea.fr',ALIGN=0.5,/NORMAL,CHARSIZE=1.8,COL=0 ;xyouts,0.5,0.1,'!D.N_COLORS:'+STRING(!D.N_COLORS),ALIGN=0.5,/NORMAL,CHARSIZE=1.8,COL=0 ; On indique la restriction 8/24 bits IF !D.N_COLORS LT (2l)^24 THEN $ user_response=DIALOG_MESSAGE('WARNING: 8 bits display. 3 color composite option disabled',/INFO) ; ��� XMANAGER ��� XMANAGER, 'Polder_Directional',TopLevelBase,/NO_BLOCK END