Bug #12723 fixed - Loading a .scg file in the CURVE bloc produced an
[scilab.git] / scilab / modules / graphics / macros / edit_curv.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) 1993 - INRIA - Serge Steer
3 // Copyright (C) 1993 - INRIA - Habib Jreij
4 // This file must be used under the terms of the CeCILL.
5 // This source file is licensed as described in the file COPYING, which
6 // you should have received as part of this distribution.  The terms
7 // are also available at
8 // http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
9
10 function [x,y,ok,gc]=edit_curv(x,y,job,tit,gc)
11     //   mod_curv  - Edition  de courbe interactive
12     //%Syntaxe
13     //  [x,y,ok]=mod_curv(xd,yd,job,tit)
14     //%Parametres
15     //  xd    :  vecteur des abscisses donnees (eventuellement [])
16     //  yd    :  vecteur des ordonnees donnees (eventuellement [])
17     //  job   :  chaine de 3 caracteres  specifiant les operations
18     //           permises:
19     //            - Si la chaine contient le caractere 'a', il est
20     //              possible d'ajouter des points aux donnees, sinon
21     //              il est seulement possible de les deplacer
22     //            - Si la chaine contient le caractere 'x', il est
23     //              possible de deplacer les points horizontalement
24     //            - Si la chaine contient le caractere 'y', il est
25     //              possible de deplacer les points verticalement
26     //  tit   : liste de trois chaines de caracteres
27     //          tit(1) : titre de la courbe (peut etre un vecteur colonne)
28     //          tit(2) : label de l'axe des abscisses
29     //          tit(3) : label de l'axe des ordonnees
30     //  x     : vecteur des abscisses resultat
31     //  y     : vecteur des ordonnees resultat
32     //  ok    : vaut %t si la sortie as ete demandee par le menu Ok
33     //           et  %f si la sortie as ete demandee par le menu Abort
34     //%menus
35     //  Ok    : sortie de l'editeur et retour de la courbe editee
36     //  Abort : sortie de l'editeur et retour au donnes initiales
37     //  Undo  : annulation de la derniere modification
38     //  Size  : changement des bornes du graphique
39     //  Grids : changement des graduations du graphique
40     //  Clear : effacement de la courbe (x=[] et y=[]) (sans quitter l'editeur)
41     //  Read  : lecture de la courbe a partir d'un fichier d'extension .xy
42     //  Save  : sauvegarde binaire (sur un fichier d'extension .xy) de
43     //          la courbe
44     //!
45     [lhs,rhs]=argn(0)
46
47     ok = %t;
48     if rhs==0 then x=[]; y=[],end;
49     if rhs==1 then y=x;x=(1:size(y,"*"))',end
50     if rhs<3  then job="axy",end
51     if rhs<4 then tit=[" "," "," "],end
52     if size(tit,"*")<3 then tit(3)=" ",end
53     //
54
55     [mx,nx] = size(x); x=x(:)
56     [my,ny] = size(y); y=y(:)
57     n = min(mx*nx,my*ny)
58     x= x(1:n);y=y(1:n);
59     xsav=x; ysav=y; xs=x; ys=y;
60     //
61     lj = length(job)
62     add=0;modx=0;mody=0
63     for k=1:lj
64         jk = part(job,k)
65         select jk
66         case "a" then add = 1,
67         case "x" then modx= 1
68         case "y" then mody= 1
69         else error(msprintf(gettext("%s: Wrong value for input argument #%d: Must be in the set {%s}.\n"), "edit_curv", 3, "a, x, y"));
70         end
71     end
72     eps = 0.03
73     symbsiz = 0.2
74     // bornes initiales du graphique
75     if rhs<5 then
76         if mx<>0 then
77             xmx = max(x); xmn = min(x)
78             ymx = max(y); ymn = min(y)
79             dx = xmx-xmn;  dy = ymx-ymn
80             if dx==0 then dx=max(xmx/2,1),end
81             xmn=xmn-dx/10;xmx=xmx+dx/10
82             if dy==0 then dy=max(ymx/2,1),end;
83             ymn=ymn-dy/10;ymx=ymx+dy/10;
84         else
85             xmn=0;ymn=0;xmx=1;ymx=1;dx=1;dy=1
86         end
87         rect=[xmn,ymn,xmx,ymx];
88         axisdata=[2 10 2 10];
89         gc = list(rect,axisdata);
90     else //** rhs=5 as in Scicos ;)
91         [rect,axisdata] = gc(1:2)
92         xmn = rect(1);
93         ymn = rect(2);
94         xmx = rect(3);
95         ymx = rect(4);
96         dx  = xmx-xmn;
97         dy  = ymx-ymn;
98     end
99
100     // Set menus and callbacks
101     menu_d = ["Read","Save","Clear"]
102     menu_e = ["Undo","Size","Replot","Ok","Abort"]
103     menus  = list(["Edit","Data"],menu_e,menu_d)
104     w="menus(2)(";rpar=")"
105     Edit=w(ones(menu_e))+string(1:size(menu_e,"*"))+rpar(ones(menu_e))
106     w="menus(3)(";rpar=")"
107     Data=w(ones(menu_d))+string(1:size(menu_d,"*"))+rpar(ones(menu_d))
108
109     curwin = max(winsid())+1;
110     scf(curwin) ;
111
112     // Disable the menus and toolbars
113     toolbar(curwin,"off");
114     delmenu(curwin,gettext("File"));
115     delmenu(curwin,gettext("Tools"));
116     delmenu(curwin,gettext("Edit"));;
117     delmenu(curwin,"?");
118
119     execstr("Edit_"+string(curwin)+"=Edit");
120     execstr("Data_"+string(curwin)+"=Data");
121     menubar(curwin,menus)
122     //
123     edit_curv_figure = gcf();
124     edit_curv_figure.figure_name = "edit_curv";
125
126     edit_curv_axes = gca();
127     edit_curv_axes.data_bounds = [rect(1),rect(2);rect(3),rect(4)]
128     edit_curv_axes.axes_visible="on";
129     edit_curv_axes.grid=[4 4];
130     if x<>[] then
131         xpolys(x*[1 1],y*[1 1],[1,-1])
132         hdl=edit_curv_axes.children.children
133     else
134         hdl=[]
135     end
136
137     xtitle(tit(1),tit(2),tit(3));
138
139
140     // -- boucle principale
141     while %t then
142         [n1,n2] = size(x);
143         npt = n1*n2 ;
144
145         [btn,xc,yc,win,Cmenu] = get_click();
146
147         //** disp([btn,xc,yc,win]); //** DEBUG only
148
149         c1 = [xc,yc];
150
151         if Cmenu=="Quit" then Cmenu="Abort",end
152         if Cmenu==[]     then Cmenu="edit",end
153         if Cmenu=="Exit" then Cmenu="Ok",end
154
155         select Cmenu
156         case [] then
157             // ce n est pas un menu
158             break
159
160         case "Ok" then    //    -- ok menu
161             rect = matrix(edit_curv_axes.data_bounds',1,4);
162             gc   = list(rect,axisdata);
163             delete(edit_curv_figure)
164             return;
165
166         case "Abort" then //    -- abort menu
167             x = xsav
168             y = ysav
169             delete(edit_curv_figure)
170             ok = %f;
171             return
172
173         case "XClose" then //** the user manually close the win
174             x = xsav
175             y = ysav
176             ok = %f;
177             return
178
179         case "Undo" then
180             x=xs;y=ys
181             if x<>[] then hdl.data=[x y]; end
182
183         case "Size" then
184             while %t
185                 [ok,xmn,xmx,ymn,ymx]=getvalue("Please input new limits",..
186                 ["xmin";"xmax";"ymin";"ymax"],..
187                 list("vec",1,"vec",1,"vec",1,"vec",1),..
188                 string([xmn;xmx;ymn;ymx]))
189                 if ~ok then break,end
190                 if xmn>xmx|ymn>ymx then
191                     messagebox("Limits are not accettable","modal");
192                 else
193                     break
194                 end
195             end
196             if ok then
197                 dx=xmx-xmn;dy=ymx-ymn
198                 if dx==0 then dx=max(xmx/2,1),xmn=xmn-dx/10;xmx=xmx+dx/10;end
199                 if dy==0 then dy=max(ymx/2,1),ymn=ymn-dy/5;ymx=ymx+dy/10;end
200                 rect=[xmn,ymn,xmx,ymx];
201                 edit_curv_axes.data_bounds=[rect(1),rect(2);rect(3),rect(4)]
202             end
203
204         case "Clear" then
205             if hdl<>[] then delete(hdl),hdl=[];end
206             x=[];y=[];
207
208         case "Read" then
209             [x,y]=readxy()
210             mx=min(prod(size(x)),prod(size(y)))
211             if mx<>0 then
212                 xmx=max(x);xmn=min(x)
213                 ymx=max(y);ymn=min(y)
214                 dx=xmx-xmn;dy=ymx-ymn
215                 if dx==0 then dx=max(xmx/2,1),xmn=xmn-dx/10;xmx=xmx+dx/10;end
216                 if dy==0 then dy=max(ymx/2,1),ymn=ymn-dy/5;ymx=ymx+dy/10;end
217             else
218                 xmn=0;ymn=0;xmx=1;ymx=1;dx=1;dy=1
219             end
220             rect=[xmn,ymn,xmx,ymx];
221             edit_curv_axes.data_bounds=[rect(1),rect(2);rect(3),rect(4)]
222             if x<>[]&y<>[] then
223                 if hdl==[] then
224                     xpolys(x(1)*[1 1],y(1)*[1 1],[1,-1])
225                     hdl=gce();hdl=hdl.children
226                 end
227                 hdl.data=[x y];
228             else
229                 if hdl<>[] then delete(hdl),end
230                 x=[];y=[];
231             end
232
233         case "Save" then
234             savexy(x,y)
235
236         case "Replot" then
237             // for compatibility only, perform nothing on purpose
238
239         case "edit" then
240             npt=prod(size(x))
241             if npt<>0 then
242                 dist=((x-ones(npt,1)*c1(1))/dx).^2+((y-ones(npt,1)*c1(2))/dy).^2
243                 [m,k]=min(dist);m=sqrt(m)
244             else
245                 m=3*eps
246             end
247             if m<eps then                 //on deplace le point
248                 xs=x;ys=y
249                 [x,y]=movept(x,y)
250             else
251                 if add==1 then
252                     xs=x;ys=y                  //on rajoute un point de cassure
253                     [x,y]=addpt(c1,x,y)
254                 end
255             end
256         end
257     end
258 endfunction
259
260
261 function [btn,xc,yc,win,Cmenu] = get_click(flag)
262     //** 05/01/09 : update for Scilab 5.1: (close code is now -1000)
263
264     if ~or(winsid()==curwin) then
265         Cmenu = "Quit";
266         return        ;
267     end
268
269     if argn(2) == 1 then
270         [btn, xc, yc, win, str] = xclick(flag);
271     else
272         [btn, xc, yc, win, str] = xclick();
273     end
274
275     if btn == -1000 then //** user close the window [X]
276         if win == curwin then
277             Cmenu = "XClose";
278         else
279             Cmenu = "Open/Set";
280         end
281         return ;
282     end
283
284     if btn == -2 then //** user select a dynamic menu
285         xc = 0; yc = 0;
286         execstr("Cmenu=" + part(str, 9:length(str) - 1) );
287         execstr("Cmenu=" + Cmenu);
288         return;
289     end
290
291     Cmenu = [];
292
293 endfunction
294
295
296 function [x,y] = addpt(c1,x,y)
297     // permet de rajouter un point de cassure
298     npt = prod(size(x))
299     c1 = c1'
300     if hdl==[] then
301         x = c1(1);
302         y = c1(2);
303         xpolys(x*[1 1],y*[1 1],[1,-1]);
304         hdl = resume(edit_curv_axes.children(1).children)
305     end
306     //recherche des intervalles en x contenant l'abscisse designee
307     kk=[]
308     if npt>1 then
309         kk=find((x(1:npt-1)-c1(1)*ones(x(1:npt-1)))..
310         .*(x(2:npt)-c1(1)*ones(x(2:npt)))<=0)
311     end
312     if  kk<>[] then
313         //    recherche du segment sur le quel on a designe un point
314         pp=[];d=[];i=0
315         for k=kk
316             i=i+1
317             pr=projaff(x(k:k+1),y(k:k+1),c1)
318             if (x(k)-pr(1))*(x(k+1)-pr(1))<=0 then
319                 pp=[pp pr]
320                 d1=rect(3)-rect(1)
321                 d2=rect(4)-rect(2)
322                 d=[d norm([d1;d2].\(pr-c1))]
323             end
324         end
325         if d<>[] then
326             [m,i]=min(d)
327             if m<eps
328                 k=kk(i)
329                 pp=pp(:,i)
330                 x=x([1:k k:npt]);x(k+1)=pp(1);
331                 y=y([1:k k:npt]);y(k+1)=pp(2);
332                 hdl.data=[x y];
333                 return
334             end
335         end
336     end
337     d1=rect(3)-rect(1)
338     d2=rect(4)-rect(2)
339     if norm([d1;d2].\([x(1);y(1)]-c1))<norm([d1;d2].\([x(npt);y(npt)]-c1)) then
340         //  -- mise a jour de x et y
341         x(2:npt+1)=x;x(1)=c1(1)
342         y(2:npt+1)=y;y(1)=c1(2)
343     else
344         //  -- mise a jour de x et y
345         x(npt+1)=c1(1)
346         y(npt+1)=c1(2)
347     end
348     hdl.data=[x y];
349 endfunction
350
351 function [x,y]=movept(x,y)
352     //on bouge un point existant
353     hdl;
354     rep(3)=-1
355     while rep(3)==-1 do
356         rep = xgetmouse();
357         xc=rep(1);yc=rep(2);c2=[xc;yc]
358         if modx==0 then c2(1)=x(k);end
359         if mody==0 then c2(2)=y(k);end
360         x(k)=c2(1);y(k)=c2(2)
361         hdl.data=[x,y];
362     end
363 endfunction
364
365
366 function [x,y] = readxy()
367
368     function xy = findPolyline(children)
369         xy = [];
370         for i = 1:length(children)
371             select children(i).type,
372             case "Polyline" then
373                 xy = children(i).data;
374                 return
375             case "Axes" then
376                 xy = findPolyline(children(i).children);
377                 return
378             case "Compound" then
379                 xy = findPolyline(children(i).children);
380                 return
381             end
382         end
383     endfunction
384
385     fn=uigetfile(["*.scg";"*.sod";"*.xy"], "", _("Select a file to load"));
386     if fn <> "" then
387         [pth, fnm, ext] = fileparts(fn);
388         flname = fnm + ext;
389
390         select ext
391         case ".scg" then
392             loaded_figure=figure("visible", "off");
393             if execstr("xload(fn, loaded_figure.figure_id)","errcatch") == 0 then
394                 loaded_figure.visible = "off";
395                 scf(edit_curv_figure);
396                 xy = findPolyline(loaded_figure.children);
397                 delete(loaded_figure);
398                 if xy <> [] then
399                     x=xy(:,1);y=xy(:,2);
400                 else
401                     messagebox(msprintf(_("%s: The file "'%s"' does not " +..
402                     "contains any "'Polyline"' graphic entity.\n"), "edit_curve", flname));
403                     return
404                 end
405             else
406                 messagebox(msprintf(_("%s: Cannot open file "'%s"' " +..
407                 "for reading.\n"), "edit_curv", flname), "modal");
408                 return
409             end
410         case ".xy" then
411             if execstr("xy = read(fn,-1,2)","errcatch") == 0 then
412                 x=xy(:,1);y=xy(:,2);
413             else
414                 messagebox(msprintf(_("%s: Cannot open file "'%s"' " +..
415                 "for reading.\n"), "edit_curv", flname), "modal");
416                 return
417             end
418         case ".sod" then
419             if execstr("load(fn)","errcatch") == 0 then
420                 x=xy(:,1);y=xy(:,2);
421             else
422                 messagebox(msprintf(_("%s: Cannot open file "'%s"' " +..
423                 "for reading.\n"), "edit_curv", flname), "modal");
424                 return
425             end
426         else
427             messagebox(_("Error in file format."), "modal");
428             return
429         end
430     else
431         x=x
432         y=y
433     end
434 endfunction
435
436
437 function savexy(x,y)
438     fn=uiputfile(["*.sod";"*.xy"], "", _("Select a file to write"));
439     if fn <> "" then
440         [pth, fnm, ext] = fileparts(fn);
441         flname = fnm + ext;
442         xy = [x y];
443         fil = fn;
444
445         select ext
446         case "" then
447             fil = fil + ".xy";
448             ext = ".xy";
449         case ".xy" then
450             // empty case fil = fn
451         case ".sod" then
452             // empty case fil = fn
453         else
454             fil = pth + fnm + ".xy";
455             ext = ".xy";
456         end
457
458         select ext
459         case ".sod" then
460             if execstr("save(fil,""xy"")","errcatch")<>0 then
461                 messagebox(msprintf(_("%s: The file "'%s"' " +..
462                 "cannot be written.\n"), "edit_curv", flname), "modal");
463                 return
464             end
465         case ".xy" then
466             isErr = execstr("write(fil,xy)","errcatch")
467             if isErr == 240 then
468                 mdelete(fil); // write cannot overwrite an existing file
469                 isErr = execstr("write(fil,xy)","errcatch");
470             end
471             if isErr <> 0 then
472                 messagebox(msprintf(_("%s: The file "'%s"' " +..
473                 "cannot be written.\n"), "edit_curv", flname), "modal");
474                 return
475             end
476         end
477     end
478 endfunction