1 /*
2  * $Id: rezone.i,v 1.2 2010-04-18 10:33:38 thiebaut Exp $
3  * Point and click rezoner, written in interpreted Yorick.
4  */
5 /* Copyright (c) 2005, The Regents of the University of California.
6  * All rights reserved.
7  * This file is part of yorick (http://yorick.sourceforge.net).
8  * Read the accompanying LICENSE file for details.
9  */
10 
11 require, "button.i";
12 require, "bowtie.i";
13 
toy_mesh(filename)14 func toy_mesh(filename)
15 /* DOCUMENT toy_mesh, filename
16      generates a toy mesh in the file FILENAME in order to be able to
17      play with the rezone function.  (FILENAME must be a string enclosed
18      in double quotes, of course.)
19    SEE ALSO: rezone
20  */
21 {
22   rt= span(1., 0., 6)(,-:1:11);
23   zt= span(0., 2., 11)(-:1:6,);
24   rt(3,3)+= 0.15;
25   zt(3,3)+= 0.15;
26   rt(3,7)+= 0.05;
27   zt(3,7)+= 0.25;
28   save, createb(filename), rt, zt;
29 }
30 
31 extern rez_load_hook;
32 /* DOCUMENT rez_load_hook
33      If non-nil, filename to be included immediately after rez.i.
34      This file can be used to set personalized default values for the
35      many parameters.
36      Some parameters may be set before loading rez.i, as well
37    SEE ALSO: rez_kstyle, rez_lstyle
38  */
39 
40 extern rez_kstyle;
41 extern rez_lstyle;
42 extern rez_color;
43 /* DOCUMENT rez_kstyle, rez_lstyle, rez_color
44      is a vector of three longs:  [type,width,color]
45      type MUST be 1, 2, 3, 4, or 5,
46      width MUST be 1, 2, 3, 4, 5, 6, 7, or 8,
47      and color MUST be -1, -2, -3, -4, -5, -6, -7, -8, -9, or -10
48 
49      Either or both parameters may be set before or after including
50      rez.i; by default:
51        rez_kstyle= [4, 1, -2]    (dashdot, thin, foreground color)
52        rez_lstyle= [1, 1, -2]    (solid, thin, foreground color)
53 
54      To distinguish K and L by color instead of type, try:
55        rez_kstyle= [1, 1, -7]    (dashdot, thin, blue)
56        rez_lstyle= [1, 1, -5]    (solid, thin, red)
57      If the variable rez_color is true (non-nil and non-zero) when
58      this file is included, then these will be the default.
59 
60    SEE ALSO: rez_load_hook
61  */
62 /* This choice distinguishes by line type.  */
63 _old_rez_color= rez_color;
64 if (is_void(rez_kstyle)) rez_kstyle= rez_color? [1, 1, -7]:[4, 1, -2];
65 if (is_void(rez_lstyle)) rez_lstyle= rez_color? [1, 1, -5]:[1, 1, -2];
66 
67 extern rez_mark;
68 /* DOCUMENT rez_mark
69      Causes rezone functions to mark bowtied or chevroned (boomeranged)
70      zones when the mesh is plotted.  MUST have one of the following values:
71        0 to not mark bowtied or chevroned zones
72        1 to put a B at the center of the positive triangle of bowtied zones
73        2 to put a C at the center of the larger wing of chevroned zones
74        3 to mark both bowtied and chevroned zones
75 
76      By default, rez_mark is 3; you may set it to a different value
77      either before or after including rez.i.
78 
79    SEE ALSO: rez_mesh, rez_next, rez_prev, rez_drag
80  */
81 if (is_void(rez_mark)) rez_mark= 3;
82 
83 _rez_on_black= 0;
84 
85 extern rez_palette;
86 /* DOCUMENT rez_palette
87      3-by-ncolors array used as a palette when rez_regs region coloring
88      is set.  The index in rez_regs is the second index into rez_palette.
89      The length 3 first index is [r,g,b].
90      The default is 15 pastels.
91    SEE ALSO: rez_regs
92  */
93 rez_palette= [[255,230,230],[230,255,230],[230,230,255],[242,242,230],
94               [230,242,242],[242,230,242],[236,249,230],[236,236,242],
95               [249,236,230],[230,236,249],[242,236,236],[230,249,236],
96               [249,230,236],[236,242,236],[236,230,249]];
97 _old_rez_palette= [];
98 
99 func rez_chk_palette
100 {
101   if (typeof(rez_palette)!=typeof(_old_rez_palette) ||
102       dimsof(rez_palette)(1)!=dimsof(_old_rez_palette)(1) ||
103       anyof(dimsof(rez_palette)!=dimsof(_old_rez_palette)) ||
104       anyof(rez_palette!=_old_rez_palette)) {
105     if (dimsof(rez_palette)(2)!=3)
106       error, "rez_palette must be [[r1,g1,b1],[r2,g2,b2],...]";
107     if (!is_array(rez_palette) || typeof(rez_palette)=="struct_instance" ||
108         typeof(rez_palette)=="string" || typeof(rez_palette)=="complex" ||
109         min(rez_palette)<0 || max(rez_palette)>255)
110       error, "rez_palette values should be between 0 and 255";
111     palette, rez_palette(1,), rez_palette(2,), rez_palette(3,);
112     _old_rez_palette= rez_palette;
113     fma;
114   }
115 }
116 
117 extern rez_regs;
118 /* DOCUMENT rez_regs
119      is a vector of region numbers which are to be drawn in the colors
120      specified in rez_palette.  Thus:
121         rez_regs= [3,5]
122      causes regions 3 and 5 to be drawn in colors.  All other regions have
123      white backgrounds.  Hilighting too many regions in this way may slow
124      down the redraws unacceptably.  To highlight all regions, use:
125         rez_regs= indgen(max(rez_ireg))
126      This won't work on monochrome monitors, of course.
127      The default is rez_regs=[].
128    SEE ALSO: rez_palette
129  */
130 
131 extern rez_adjust_mesh;
132 /* DOCUMENT rez_adjust_mesh
133      is an optional hook function which is called after any change to the
134      mesh (e.g.- by dragging points) has been made.  If it is defined, it
135      may modify the external variables rez_rt and rez_zt.  This hook can
136      be used, for example, to force points along some k or l line to lie
137      along a symmetry line.
138    SEE ALSO: rezone, rez_all, rez_mesh
139  */
140 
rez_plm(flag,adj_check)141 func rez_plm(flag, adj_check)
142 {
143   if (adj_check && is_func(rez_adjust_mesh)) rez_adjust_mesh;
144 
145   fma;
146 
147   extern rez_kstyle, rez_lstyle;
148   if (rez_color!=_old_rez_color) {
149     rez_kstyle= rez_color? [1, 1, -7]:[4, 1, -2];
150     rez_lstyle= rez_color? [1, 1, -5]:[1, 1, -2];
151     _old_rez_color= rez_color;
152   }
153 
154   if (!is_void(rez_regs)) {
155     rez_chk_palette;
156     n= numberof(rez_regs);
157     colors= array(char, dimsof(rez_rt)(2), dimsof(rez_rt)(3));
158     for (i=1 ; i<=n ; i++) {
159       reg= rez_regs(i);
160       if (noneof(rez_ireg==reg) || reg<=0) continue;
161       colors(where(rez_ireg==reg))= i-1;
162       plf, colors, rez_rt, rez_zt, rez_ireg, legend=string(0), region=reg;
163     }
164   } else if (_rez_on_black) {
165     rez_ptexist;
166     list= where(rez_ptx);
167     r= rez_rt(list);
168     z= rez_zt(list);
169     pli, [['\0']], min(z), min(r), max(z), max(r);
170   }
171 
172   plm, rez_rt, rez_zt, rez_ireg, legend=string(0), inhibit=1,
173        color= rez_kstyle(3), width= rez_kstyle(2), type= rez_kstyle(1);
174   plm, rez_rt, rez_zt, rez_ireg, legend=string(0), inhibit=2,
175        color= rez_lstyle(3), width= rez_lstyle(2), type= rez_lstyle(1);
176 
177   if (rez_mark&3) {
178     extern rez_map;
179     local rr, zz;
180     if (flag || is_void(flag)) {
181       if (_rez_polar) {
182         zt= rez_zt*cos(rez_rt);
183         rt= rez_zt*sin(rez_rt);
184       } else {
185         zt= rez_zt;
186         rt= rez_rt;
187       }
188       rez_map= bowtie(rt,zt,rez_ireg);
189     }
190     for (i=1 ; i<=2 ; i++) {
191       if (!(rez_mark&i)) continue;
192       rez_getrz, where(rez_map==(i-1));
193       if (!is_void(rr)) {
194         a1= (rr(2,2,)-rr(2,1,))*(zz(2,1,)-zz(1,1,)) -
195           (zz(2,2,)-zz(2,1,))*(rr(2,1,)-rr(1,1,));
196         a2= (rr(1,1,)-rr(1,2,))*(zz(1,2,)-zz(2,2,)) -
197           (zz(1,1,)-zz(1,2,))*(rr(1,2,)-rr(2,2,));
198         a3= (rr(2,1,)-rr(1,1,))*(zz(1,1,)-zz(1,2,)) -
199           (zz(2,1,)-zz(1,1,))*(rr(1,1,)-rr(1,2,));
200         if (i==1) {
201           /* this is a magic trick for bowtied zones */
202           index= ((a3>=0.) | (a1>=0.)<<1 | (a2>=0.)<<2) - 1;
203           p1= [1,0,3,2](index);
204           p2= [3,1,2,0](index);
205           p3= [2,3,0,1](index);
206           p4= [0,2,1,3](index);
207           index= indgen(1:numberof(rr):4);
208           p1+= index;
209           p2+= index;
210           p3+= index;
211           p4+= index;
212           /* now p1 p2 p3 p4 are the indices of the points in (rr,zz)
213              with p1 p2 being the positive edge of the bowtied zone,
214              so that p1 p3 and p2 p4 cross */
215           r1= rr(p1);
216           z1= zz(p1);
217           r2= rr(p2);
218           z2= zz(p2);
219           r3= rr(p3);
220           z3= zz(p3);
221           r4= rr(p4);
222           z4= zz(p4);
223           fa= (r3-r2)*(z4-z1);
224           fb= -(r4-r1)*(z3-z2);
225           det= fa+fb;
226           fa/= det;
227           fb/= det;
228           rr= r1*fa + r2*fb + (r3-r2)*(r4-r1)*(z2-z1)/det;
229           zz= z2*fa + z1*fb - (z3-z2)*(z4-z1)*(r2-r1)/det;
230           rr= (rr+r1+r2)/3.0;
231           zz= (zz+z1+z2)/3.0;
232           marker= 'B';
233           legend= "B: bowtied zones";
234         } else {
235           a4= (rr(1,2,)-rr(2,2,))*(zz(2,2,)-zz(2,1,)) -
236             (zz(1,2,)-zz(2,2,))*(rr(2,2,)-rr(2,1,));
237           r1= (rr(1,1,)+rr(2,1,)+rr(2,2,))/3.0;
238           z1= (zz(1,1,)+zz(2,1,)+zz(2,2,))/3.0;
239           r2= (rr(1,1,)+rr(2,2,)+rr(1,2,))/3.0;
240           z2= (zz(1,1,)+zz(2,2,)+zz(1,2,))/3.0;
241           r3= (rr(2,1,)+rr(1,1,)+rr(1,2,))/3.0;
242           z3= (zz(2,1,)+zz(1,1,)+zz(1,2,))/3.0;
243           r4= (rr(1,2,)+rr(2,2,)+rr(2,1,))/3.0;
244           z4= (zz(1,2,)+zz(2,2,)+zz(2,1,))/3.0;
245           mask= (a1>0. & a2>0.);
246           which= [a1*mask,a2*mask,a3*(1-mask),a4*(1-mask)](,mxx);
247           n= numberof(a1);
248           list= indgen(n)+n*(which-1);
249           rr= [r1,r2,r3,r4](list);
250           zz= [z1,z2,z3,z4](list);
251           marker= 'C';
252           legend= "C: chevroned zones";
253         }
254         plg,rr,zz,type=0,marker=marker,legend=legend;
255       }
256     }
257   }
258 }
259 
260 _rez_polar= 0n;
261 
262 func rez_toggle
263 {
264   zt= rez_zt;
265   rt= rez_rt;
266   _rez_polar= !_rez_polar;
267   if (_rez_polar) {
268     rez_zt= abs(rt,zt);
269     rez_rt= atan(rt,zt+1.e-99);
270   } else {
271     rez_zt= zt*cos(rt);
272     rez_rt= zt*sin(rt);
273   }
274 }
275 
276 /* These four parameters specify the viewport position, which is actually
277    a function of the stylesheet being used, and potentially changes as
278    a function of window or coordinate system within the window.  The numbers
279    here should work decently for the work.gs and boxed.gs styles.  If you
280    set them very large, the only side effect is that clicking way outside
281    the coordinate system (e.g.- missing the Done or Undo button) will pick
282    up the nearest mesh vertex).  This is not that unreasonable a behavior,
283    especially since any miscue can be undone.  See rez_load_hook.  */
284 _rez_xvp=  (0.615+0.175)*0.5;
285 _rez_dxvp= (0.615-0.175)*0.5;
286 _rez_yvp=  (0.895+0.455)*0.5;
287 _rez_dyvp= (0.895-0.455)*0.5;
288 /* Following setup could be placed in rez_load_hook to allow any style:
289   _rez_xvp=  0.5;
290   _rez_dxvp= 0.6;
291   _rez_yvp=  0.5;
292   _rez_dyvp= 0.6;
293  */
294 
295 func rezone(filename, all=, quiet=)
296 /* DOCUMENT rezone, filename
297          or rezone
298 
299      Invoke the mouse-driven rezoner.  Input is taken from variables
300      rt, zt, and ireg in the file FILENAME (which is prompted for if
301      omitted).  Output is written to a different file as rt, zt, and
302      ireg.  The output file also contains copies rez_rt, rez_zt, and
303      rez_ireg in case the mesh under a different name is desirable,
304      as well as rez_rt0, rez_zt0, and rez_ireg0, which are the original
305      mesh.
306 
307      If you click on [Escape], you may continue rezoning where you left
308      off by typing   rezone   with no arguments.
309 
310      When you are finished, click [OK] to write the output file.
311 
312      Use [Zoom or Pan] and [Set Styles] to change the plot limits or
313      line colors and styles.  The [Zoom or Pan] screen has buttons which
314      "warp" you to each bowtied or chevroned "problem" zone, as well as
315      a button to toggle between rectangular and polar coordinates.
316 
317      Click [Drag Points] to drag points one at a time with the mouse.
318 
319      Click [Adjust Line] to smooth the points on logical line segments.
320      You first click on the endpoints P and Q, then click a button to
321      smooth or equal space the poionts between P and Q, or drag any
322      point between P and Q to establish equal ratio zones ("ER" operation).
323 
324      Click [Adjust Region] to smooth the points in logically rectangular
325      regions.  You first click on the opposite corners P and R of the
326      rectangle PQRS, then click a button to smooth the interior points,
327      or click on a point on one of the four edges to transfer the spacing
328      on that edge throughout the region PQRS ("EQ" operation).
329 
330      The [Undo] (or [Redo]) button removes the effect of the most
331      recent drag points, adjust line, or adjust region operation.
332 
333      Hints:
334      (0) After [Escape], the current mesh is in the variables
335          rez_zt, rez_rt, and rez_ireg.  You can change these
336          variables "by hand" before restarting rezone to make
337          algebraic adjustments.
338      (1) Switch to polar coordinates during an [Adjust Line] or
339          [Adjust Region] in order to get points to lie along a
340          circular arc.  If your center point is not (0,0), you
341          will need to [Escape] and subtract your center point
342          from the rez_zt and rez_rt variables yourself, then
343          [Escape] a second time to restore the proper coordinates
344          before you write the output file.
345      (2) You can select a center point as the second point during
346          [Adjust Line] or [Adjust Region].  When you do this, the
347          K (or L) value of this second point will be the same as
348          that of the first point -- otherwise there is no way to
349          distinguish among all of the logical points at the center.
350          In an [Adjust Region], the center point will be labeled
351          Q instead of R as usual, and you will need to choose a
352          third point (S) to complete the rectangle PQRS.
353      (3) If you set the variable rez_color=1 before you include
354          rezone.i, you will get K lines and L lines drawn in different
355          colors instead of the default (which is K lines dashdot and
356          L lines solid).
357      (4) If you have a color monitor, you can set rez_regs before
358          invoking rezone in order to highlight a list of regions.
359 
360      The ALL keyword will be passed to the nbow function, which will
361      not be called if the QUIET keyword is non-nil and non-zero.  By
362      default, a short summary of bowtied and chevroned zones is printed.
363 
364      If you need help on how to use one of the screens, try getting
365      help on the appropriate on of these see-also topics, e.g.-
366         help, rez_style
367      to get help on the [Set Styles] screen.
368 
369    SEE ALSO: rez_all, rez_drag, rez_ladj, rez_radj, rez_zoom, rez_style,
370              rez_color, rez_regs, rez_adjust_mesh, toy_mesh
371  */
372 {
373   extern rez_name;
374   if (is_void(filename)) {
375     if (is_void(rez_name)) {
376       filename= "";
377       read, format="%s", prompt="Name of Z-file: ", filename;
378     }
379   }
380   if (!is_void(filename)) {
381     /* begin a new rezone */
382     for (i=1 ; i<=2 ; i++) {
383       if (!is_void(open(filename,"rb",1))) break;
384       write, "Cannot open "+filename;
385       read, format="%s", prompt="Name of Z-file: ", filename;
386     }
387     if (i>2) {
388       write, "Quitting rezone";
389       return;
390     }
391     rez_mesh, openb(filename), quiet=quiet, all=all;
392     if (!is_void(rez_zt) && !is_void(rez_rt)) rez_name= filename;
393     write, "For help, click [Escape], then type:    help, rezone";
394   }
395 
396   esca= rez_all();
397   if (_rez_polar) rez_toggle;
398   if (esca) return;
399 
400   default= rez_name+"_rez";
401   for (i=1 ; i<=3 ; i++) {
402     line=
403       rdline(prompt="Output filename (default "+default+", ? to escape): ");
404     line= strtok(line)(1);
405     if (!line) line= default;
406     else if (line=="?") line= string(0);
407     if (line!=rez_name) break;
408   }
409   if (!line || line==rez_name) {
410     write, "Escaping from rezone -- to resume, type    rezone";
411     return;
412   }
413 
414   zt= rez_zt;
415   rt= rez_rt;
416   ireg= rez_ireg;
417   at_pdb_close|= 1;
418   save, createb(line), zt, rt, ireg, rez_zt, rez_rt, rez_ireg,
419     rez_zt0, rez_rt0, rez_ireg0;
420 
421   rez_name= [];
422 }
423 
rez_all(dummy)424 func rez_all(dummy)
425 /* DOCUMENT rez_all
426      Click on [Drag Points] to drag points around with the mouse with
427      rez_drag.
428 
429      Click on [Adjust Line] to adjust points along a line segment with
430      rez_ladj.
431 
432      Click on [Adjust Region] to adjust points in a rectangular region
433      with rez_radj.
434 
435      Click on the [Undo] button to undo the previous change.
436      Click on the [Redo] button to redo the previous undo.
437      Click on the [Revert] to return to the original mesh.
438 
439      When you are finished moving points around, click on [OK].
440      Click on [Escape] to exit with a non-zero return value.
441 
442      Click on [Zoom or Pan] to change the plot limits (see rez_zoom).
443 
444      Click on [Set Styles] to change the line styles or colors (see
445      rez_style).
446 
447    SEE ALSO: rez_ladj, rez_mesh, rez_zoom, rez_style, rez_adjust_mesh
448  */
449 {
450   done= Button(text="OK",x=.203,y=.895,dx=.020,dy=.012);
451   undo= Button(text="Undo",x=.254,y=.895,dx=.025,dy=.012);
452   esca= Button(text="Escape",x=.344,y=.895,dx=.035,dy=.012);
453   zorp= Button(text="Zoom or Pan",x=.464,y=.895,dx=.054,dy=.012);
454   sets= Button(text="Set Styles",x=.569,y=.895,dx=.045,dy=.012);
455   drag= Button(text="Drag Points",x=.240,y=.375,dx=.054,dy=.012);
456   ladj= Button(text="Adjust Line",x=.350,y=.375,dx=.050,dy=.012);
457   radj= Button(text="Adjust Region",x=.468,y=.375,dx=.062,dy=.012);
458   reve= Button(text="Revert",x=.577,y=.375,dx=.030,dy=.012);
459 
460   rez_plm, 1;
461   button_plot, done, undo, esca, zorp, sets, drag, ladj, radj, reve;
462 
463   zt= zt2= rez_zt;
464   rt= rt2= rez_rt;
465 
466   for (;;) {
467     m= mouse(1, 2, "");
468     if (is_void(m)) { rdline,prompt=""; continue; }
469     x= m(5);
470     y= m(6);
471     if (button_test(done,x,y)) break;
472     if (button_test(esca,x,y)) {
473       write, "Escaping from rezone -- to resume, type    rezone";
474       rez_plm,1;
475       return 1;
476     }
477     if (button_test(undo,x,y)) {
478       if (undo.text=="Undo") {
479         rez_zt= zt;
480         rez_rt= rt;
481         undo.text= "Redo";
482       } else {
483         rez_zt= zt2;
484         rez_rt= rt2;
485         undo.text= "Undo";
486       }
487       rez_plm, 1;
488     } else if (button_test(reve,x,y)) {
489       zt= rez_zt;
490       rt= rez_rt;
491       undo.text= "Undo";
492       rez_zt= zt2= rez_zt0;
493       rez_rt= rt2= rez_rt0;
494       rez_plm, 1;
495     } else if (button_test(zorp,x,y)) {
496       rez_zoom;
497       rez_plm, 0;
498     } else if (button_test(sets,x,y)) {
499       rez_style;
500       rez_plm, 0;
501     } else if (button_test(drag,x,y)) {
502       zt= rez_zt;
503       rt= rez_rt;
504       undo.text= "Undo";
505       rez_drag;
506       zt2= rez_zt;
507       rt2= rez_rt;
508     } else if (button_test(ladj,x,y)) {
509       zt= rez_zt;
510       rt= rez_rt;
511       undo.text= "Undo";
512       rez_ladj;
513       zt2= rez_zt;
514       rt2= rez_rt;
515     } else if (button_test(radj,x,y)) {
516       zt= rez_zt;
517       rt= rez_rt;
518       undo.text= "Undo";
519       rez_radj;
520       zt2= rez_zt;
521       rt2= rez_rt;
522     } else {
523       rez_ding;
524       continue;
525     }
526     button_plot, done, undo, esca, zorp, sets, drag, ladj, radj, reve;
527   }
528 
529   rez_plm, 1;
530   return 0;
531 }
532 
533 func rez_drag
534 /* DOCUMENT rez_drag
535      Allow points in the rezone mesh to be dragged around with
536      the mouse.  Press mouse button near a vertex, move mouse
537      to desired position of that vertex, and release button.
538      If the point where you click is less than twice the distance to the
539      second closest point than to the nearest point, the point will not
540      be moved (you will hear a beep when you release the button).
541      Click on the [Undo] button to undo the previous move; you can undo
542      up to 100 previous moves by successive [Undo] clicks.
543 
544      When you are finished moving points around, click on [OK].
545 
546      Click on [Zoom or Pan] to change the plot limits (see rez_zoom).
547 
548      Click on [Set Styles] to change the line styles or colors (see
549      rez_style).
550 
551    SEE ALSO: rez_ladj, rez_radj, rez_mesh, rez_zoom, rez_style
552  */
553 {
554   done= Button(text="OK",x=.203,y=.895,dx=.020,dy=.012);
555   undo= Button(text="Undo",x=.254,y=.895,dx=.025,dy=.012);
556   lab1= Button(text="Drag points.",x=.344,y=.895,dx=.050,dy=.012,width=-1);
557   zorp= Button(text="Zoom or Pan",x=.464,y=.895,dx=.054,dy=.012);
558   sets= Button(text="Set Styles",x=.569,y=.895,dx=.045,dy=.012);
559 
560   rez_plm, 1;
561   button_plot, done, undo, lab1, zorp, sets;
562 
563   list= array(0.0, 3, 100);  /* keep last 100 moves for undo */
564 
565   kmax= dimsof(rez_rt)(2);
566   for (;;) {
567     m= mouse(1, 2, "");
568     if (is_void(m)) { rdline,prompt=""; continue; }
569     flag= j= 0;
570     if (button_test(done,m(5),m(6))) break;
571     if (button_test(undo,m(5),m(6))) {
572       j= long(list(1,1));
573       zt= list(2,1);
574       rt= list(3,1);
575       list(,1:-1)= list(,2:0);
576       list(,0)= 0.0;
577       flag= 1;
578     } else if (button_test(zorp,m(5),m(6))) {
579       rez_zoom;
580       flag= j= 2;
581     } else if (button_test(sets,m(5),m(6))) {
582       rez_style;
583       flag= j= 2;
584     } else if (abs(_rez_xvp-m(5))<=_rez_dxvp ||
585                abs(_rez_yvp-m(6))<=_rez_dyvp) {
586       j= rez_find(m(1), m(2));
587       if (numberof(_rez_center)) j= 0;
588       zt= m(3);
589       rt= m(4);
590     }
591     if (j<1) {
592       rez_ding;
593     } else {
594       if (flag<2) {
595         if (!flag) {
596           list(,2:0)= list(,1:-1);
597           list(1,1)= j;
598           list(2,1)= rez_zt(j);
599           list(3,1)= rez_rt(j);
600         }
601         rez_zt(j)= zt;
602         rez_rt(j)= rt;
603       }
604       rez_plm, (flag<2), 1;
605       button_plot, done, undo, lab1, zorp, sets;
606       if (!flag) {
607         text= swrite(format="moved (%ld,%ld)",(j-1)%kmax+1,(j-1)/kmax+1);
608         plt, text, 0.35, 0.375;
609       }
610     }
611   }
612 
613   rez_plm, 1;
614 }
615 
616 func rez_ladj
617 /* DOCUMENT rez_ladj
618      Adjust the points along a logical line segment PQ:
619 
620      Click on [Set P] or [Set Q] to set the endpoints of the segment.
621      When P and Q have been set, click [OK]; this button will
622      read [Cancel] if P and Q do not have either the same K or the
623      same L index.
624 
625      Click on [Smooth] to smooth the points along PQ.
626 
627      Click on [Equal Space] to make the points along PQ equally spaced.
628      This forces PQ to be a straight line.
629 
630      Drag any point between P and Q to get equal ratio spacing of all
631      the points between P and Q.  This also forces PQ to be a straight
632      line; if PQ is initially curved, you may want to click on
633      [Equal Space] before you attempt to drag points.
634 
635      Click on the [Undo] button to undo the previous adjustment; you can
636      undo up to 20 previous adjustments by successive [Undo] clicks.
637 
638      When you are finished adjusting lines, click on [OK].
639 
640      Click on [Zoom or Pan] to change the plot limits (see rez_zoom).
641 
642      Click on [Set Styles] to change the line styles or colors (see
643      rez_style).
644 
645      Hint:
646          You can select a center point as the second point during
647          rez_ladj.  When you do this, the K (or L) value of this second
648          point will be the same as that of the first point --
649          otherwise there is no way to distinguish among all of the
650          logical points at the center.
651 
652    SEE ALSO: rez_drag, rez_radj, rez_mesh, rez_zoom, rez_style
653  */
654 {
655   done= Button(text="OK",x=.203,y=.895,dx=.020,dy=.012);
656   undo= Button(text="Undo",x=.254,y=.895,dx=.025,dy=.012);
657   lab1= Button(text="Adjust line.",x=.344,y=.895,dx=.050,dy=.012,width=-1);
658   zorp= Button(text="Zoom or Pan",x=.464,y=.895,dx=.054,dy=.012);
659   sets= Button(text="Set Styles",x=.569,y=.895,dx=.045,dy=.012);
660 
661   setp= Button(text="Set P",x=.208,y=.375,dx=.027,dy=.012);
662   setq= Button(text="Set Q",x=.268,y=.375,dx=.027,dy=.012);
663   drag= Button(text="Drag for ER",x=.355,y=.375,
664                dx=.035,dy=.012,width=-1);
665   smth= Button(text="Smooth",x=.454,y=.375,dx=.035,dy=.012);
666   eqsp= Button(text="Equal Space",x=.550,y=.375,dx=.054,dy=.012);
667 
668   mode= 1;
669   jP= jQ= oldjP= oldjQ= 0;
670   rez_plm, 1;
671   kmax= dimsof(rez_rt)(2);
672   lab1.text= "Select P.";
673   setp.text= "Set Q";
674   done.text= "Cancel";
675   done.dx= 0.033;
676   button_plot, done, lab1, zorp, sets, setp;
677 
678   for (;;) {
679     m= mouse(1, 2, "");
680     if (is_void(m)) { rdline,prompt=""; continue; }
681     x= m(5);
682     y= m(6);
683     if (button_test(zorp,x,y)) {
684       rez_zoom;
685     } else if (button_test(sets,x,y)) {
686       rez_style;
687     } else if (button_test(setp,x,y)) {
688       mode= 1 + (setp.text!="Set P");
689       if (mode==1) {
690         lab1.text= "Select P.";
691         setp.text= "Set Q";
692       } else {
693         lab1.text= "Select Q.";
694         setp.text= "Set P";
695       }
696 
697     } else if (mode) {
698       if (button_test(done,x,y)) {
699         if (done.text=="Cancel") {
700           if (!oldjP || !oldjQ) break;
701           jP= oldjP;
702           jQ= oldjQ;
703         } else {
704           if (kP==kQ) {
705             k= kP;
706             l= rez_range(min(lP,lQ):max(lP,lQ));
707           } else {
708             l= lP;
709             k= rez_range(min(kP,kQ):max(kP,kQ));
710           }
711           zt= rez_zt(k,l);
712           rt= rez_rt(k,l);
713           list= array([zt,rt], 20);  /* keep last 20 for undo */
714         }
715         lab1.text= "Adjust line.";
716         setp.text= "Set P";
717         mode= 0;
718       } else if (abs(_rez_xvp-x)<=_rez_dxvp ||
719                abs(_rez_yvp-y)<=_rez_dyvp) {
720         j= rez_find(m(1), m(2));
721         if (numberof(_rez_center)>1) {
722           kc= (_rez_center-1)%kmax + 1;
723           lc= (_rez_center-1)/kmax + 1;
724           if (noneof(kc-kc(1))) kc= kc(1);
725           else if (noneof(lc-lc(1))) lc= lc(1);
726           if (mode==1 && jQ>0) {
727             kd= (jQ-1)%kmax + 1;
728             ld= (jQ-1)/kmax + 1;
729             if (numberof(kc)==1 && kc!=kd && anyof(lc==ld))
730               j= kc + (ld-1)*kmax;
731             else if (numberof(lc)==1 && lc!=ld && anyof(kc==kd))
732               j= kd + (lc-1)*kmax;
733           } else if (mode!=1 && jP>0) {
734             kd= (jP-1)%kmax + 1;
735             ld= (jP-1)/kmax + 1;
736             if (numberof(kc)==1 && kc!=kd && anyof(lc==ld))
737               j= kc + (ld-1)*kmax;
738             else if (numberof(lc)==1 && lc!=ld && anyof(kc==kd))
739               j= kd + (lc-1)*kmax;
740           }
741         }
742         if (j<1) {
743           rez_ding;
744           continue;
745         } else {
746           if (mode==1) jP= j;
747           else jQ= j;
748           kP= (jP-1)%kmax + 1;
749           lP= (jP-1)/kmax + 1;
750           kQ= (jQ-1)%kmax + 1;
751           lQ= (jQ-1)/kmax + 1;
752         }
753       } else {
754         rez_ding;
755         continue;
756       }
757 
758     } else {
759       if (button_test(done,x,y)) break;
760       if (button_test(undo,x,y)) {
761         rez_zt(k,l)= list(,1,1);
762         rez_rt(k,l)= list(,2,1);
763         list(,,1:-1)= list(,,2:0);
764       } else if (button_test(setq,x,y)) {
765         oldjP= jP;
766         oldjQ= jQ;
767         lab1.text= "Select Q.";
768         mode= 2;
769       } else if (button_test(smth,x,y)) {
770         zt= rez_zt(k,l);
771         if (numberof(zt)>2) {
772           rt= rez_rt(k,l);
773           list(,,2:0)= list(,,1:-1);
774           list(,1,1)= zt;
775           list(,2,1)= rt;
776           zt(2:-1)= zt(zcen)(zcen);
777           rt(2:-1)= rt(zcen)(zcen);
778           rez_zt(k,l)= zt;
779           rez_rt(k,l)= rt;
780         }
781       } else if (button_test(eqsp,x,y)) {
782         zt= rez_zt(k,l);
783         n= numberof(zt);
784         if (n>2) {
785           rt= rez_rt(k,l);
786           list(,,2:0)= list(,,1:-1);
787           list(,1,1)= zt;
788           list(,2,1)= rt;
789           rez_zt(k,l)= span(zt(1), zt(0), n);
790           rez_rt(k,l)= span(rt(1), rt(0), n);
791         }
792       } else if (abs(_rez_xvp-x)<=_rez_dxvp ||
793                abs(_rez_yvp-y)<=_rez_dyvp) {
794         j= rez_find(m(1), m(2));
795         if (j<=min(jP,jQ) || j>=max(jP,jQ) ||
796             (kP==kQ && abs(j-jP)%kmax)) {
797           rez_ding;
798           continue;
799         } else {
800           zP= rez_zt(jP);
801           rP= rez_rt(jP);
802           zQ= rez_zt(jQ);
803           rQ= rez_rt(jQ);
804           zx= m(3)-zP;
805           rx= m(4)-rP;
806           za= zQ-zP;
807           ra= rQ-rP;
808           /* set sx to projection of new point onto PQ, normalized to
809              lie between 0 (at P) and 1 (at Q) */
810           sx= (za*zx+ra*rx)/abs(za,ra,1.e-35)^2;
811           if (sx>0. && sx<1.) {
812             zt= rez_zt(k,l);
813             rt= rez_rt(k,l);
814             list(,,2:0)= list(,,1:-1);
815             list(,1,1)= zt;
816             list(,2,1)= rt;
817             n= numberof(zt)-1;  /* already guaranteed >1 */
818             if (kP==kQ) m= abs((j-1)/kmax + 1 - lP);
819             else m= abs((j-1)%kmax + 1 - kP);
820             m= 1./m;
821             r= rez_solve(1./sx, n*m)^m;
822             sa= spanl(1., r^(n-1), n)(cum);
823             sx= [0.0, sa(0)];
824             zt= interp([zP,zQ], sx, sa);
825             rt= interp([rP,rQ], sx, sa);
826             if (kP>kQ || lP>lQ) {
827               zt= zt(0:1:-1);
828               rt= rt(0:1:-1);
829             }
830             rez_zt(k,l)= zt;
831             rez_rt(k,l)= rt;
832           } else {
833             rez_ding;
834             continue;
835           }
836         }
837       } else {
838         rez_ding;
839         continue;
840       }
841     }
842     rez_plm, !mode, 1;
843     if (!mode || (jP && jQ && ((kQ==kP) ~ (lQ==lP)))) {
844       done.text= "OK";
845       done.dx= 0.020;
846     } else {
847       done.text= "Cancel";
848       done.dx= 0.033;
849     }
850     button_plot, done, lab1, zorp, sets, setp;
851     if (jP) plg, rez_rt(kP,lP), rez_zt(kP,lP),
852       marker='P', type=0, legend=string(0);
853     if (jQ) plg, rez_rt(kQ,lQ), rez_zt(kQ,lQ),
854       marker='Q', type=0, legend=string(0);
855     if (!mode) button_plot, undo, setq, drag, smth, eqsp;
856     else if (jP || jQ) {
857       text= jP? swrite(format="P=(%ld,%ld)",kP,lP) : "";
858       if (jQ) text+= swrite(format="    Q=(%ld,%ld)",kQ,lQ);
859       plt, text, 0.35, 0.375;
860     }
861   }
862 
863   rez_plm, 1;
864 }
865 
866 func rez_radj
867 /* DOCUMENT rez_radj
868      Adjust the points in a logical rectangle PQRS:
869 
870      Click on [Set P] or [Set R] to set the endpoints of the segment.
871      When P and R have been set, click [OK]; this button will
872      read [Cancel] if P and R have the same K or the same L index.
873 
874      Click on a point on any edge of PQRS (but not one of the corners)
875      to copy the spacings on that edge throughout the entire region.
876      All of the lines of the same type (K-line or L-line) as the edge
877      you clicked on will become straight lines.
878 
879      Click on [Smooth] to smooth the points interior to PQRS.
880      Click on [Smooth 4] to perform the smooth operation four times.
881 
882      Click on the [Undo] button to undo the previous adjustment; you can
883      undo up to 10 previous adjustments by successive [Undo] clicks.
884 
885      When you are finished adjusting regions, click on [OK].
886 
887      Click on [Zoom or Pan] to change the plot limits (see rez_zoom).
888 
889      Click on [Set Styles] to change the line styles or colors (see
890      rez_style).
891 
892      Hint:
893          You can select a center point as the second point during
894          rez_radj.  When you do this, the K (or L) value of this second
895          point will be the same as that of the first point --
896          otherwise there is no way to distinguish among all of the
897          logical points at the center.  The center point will be labeled
898          Q instead of R as usual, and you will need to choose a third
899          point (S) to complete the rectangle PQRS.
900 
901    SEE ALSO: rez_drag, rez_ladj, rez_mesh, rez_zoom, rez_style
902  */
903 {
904   done= Button(text="OK",x=.203,y=.895,dx=.020,dy=.012);
905   undo= Button(text="Undo",x=.254,y=.895,dx=.025,dy=.012);
906   lab1= Button(text="Adjust region.",x=.344,y=.895,dx=.050,dy=.012,width=-1);
907   zorp= Button(text="Zoom or Pan",x=.464,y=.895,dx=.054,dy=.012);
908   sets= Button(text="Set Styles",x=.569,y=.895,dx=.045,dy=.012);
909 
910   setp= Button(text="Set P",x=.208,y=.375,dx=.027,dy=.012);
911   setr= Button(text="Set R",x=.268,y=.375,dx=.027,dy=.012);
912   drag= Button(text="Click edge for EQ",x=.371,y=.375,
913                dx=.035,dy=.012,width=-1);
914   smth= Button(text="Smooth",x=.480,y=.375,dx=.035,dy=.012);
915   eqsp= Button(text="Smooth 4",x=.563,y=.375,dx=.041,dy=.012);
916 
917   mode= 1;
918   jP= jR= jQ= oldjP= oldjR= 0;
919   rez_plm, 1;
920   kmax= dimsof(rez_rt)(2);
921   lab1.text= "Select P.";
922   setp.text= "Set R";
923   done.text= "Cancel";
924   done.dx= 0.033;
925   button_plot, done, lab1, zorp, sets, setp;
926 
927   for (;;) {
928     m= mouse(1, 2, "");
929     if (is_void(m)) { rdline,prompt=""; continue; }
930     x= m(5);
931     y= m(6);
932     if (button_test(zorp,x,y)) {
933       rez_zoom;
934     } else if (button_test(sets,x,y)) {
935       rez_style;
936     } else if (button_test(setp,x,y)) {
937       mode= 1 + (setp.text!="Set P");
938       if (mode==1) {
939         lab1.text= "Select P.";
940         setp.text= "Set R";
941       } else {
942         lab1.text= "Select R.";
943         setp.text= "Set P";
944       }
945       jQ= 0;
946 
947     } else if (mode) {
948       if (button_test(done,x,y)) {
949         if (done.text=="Cancel") {
950           if (!oldjP || !oldjR) break;
951           jP= oldjP;
952           jR= oldjR;
953         } else {
954           k0= min(kP,kR);
955           k1= max(kP,kR);
956           l0= min(lP,lR);
957           l1= max(lP,lR);
958           zt= rez_zt(k0:k1,l0:l1);
959           rt= rez_rt(k0:k1,l0:l1);
960           list= array([zt,rt], 10);  /* keep last 10 for undo */
961         }
962         lab1.text= "Adjust region.";
963         setp.text= "Set P";
964         mode= jQ= 0;
965       } else if (abs(_rez_xvp-x)<=_rez_dxvp ||
966                  abs(_rez_yvp-y)<=_rez_dyvp) {
967         j= rez_find(m(1), m(2));
968         mold= mode;
969         if (numberof(_rez_center)>1) {
970           if (mode==2 && jP>0) {
971             kc= (_rez_center-1)%kmax + 1;
972             lc= (_rez_center-1)/kmax + 1;
973             if (noneof(kc-kc(1))) kc= kc(1);
974             else if (noneof(lc-lc(1))) lc= lc(1);
975             kd= (jP-1)%kmax + 1;
976             ld= (jP-1)/kmax + 1;
977             if (numberof(kc)==1 && kc!=kd && anyof(lc==ld))
978               j= kc + (ld-1)*kmax;
979             else if (numberof(lc)==1 && lc!=ld && anyof(kc==kd))
980               j= kd + (lc-1)*kmax;
981             lab1.text= "Select S.";
982             mode= 3;
983           } else {
984             j= 0;
985           }
986         }
987         if (j<1) {
988           rez_ding;
989           continue;
990         } else {
991           if (mode==1) jP= j;
992           else if (mode==2) jR= j;
993           else if (mode!=mold) jQ= j;
994           else if (kP==kQ) jR= (j-1)%kmax + 1 + (lQ-1)*kmax;
995           else jR= kQ + ((j-1)/kmax)*kmax;
996           kP= (jP-1)%kmax + 1;
997           lP= (jP-1)/kmax + 1;
998           kR= (jR-1)%kmax + 1;
999           lR= (jR-1)/kmax + 1;
1000           kQ= (jQ-1)%kmax + 1;
1001           lQ= (jQ-1)/kmax + 1;
1002         }
1003       } else {
1004         rez_ding;
1005         continue;
1006       }
1007 
1008     } else {
1009       if (button_test(done,x,y)) break;
1010       if (button_test(undo,x,y)) {
1011         rez_zt(k0:k1,l0:l1)= list(,,1,1);
1012         rez_rt(k0:k1,l0:l1)= list(,,2,1);
1013         list(,,,1:-1)= list(,,,2:0);
1014       } else if (button_test(setr,x,y)) {
1015         oldjP= jP;
1016         oldjR= jR;
1017         lab1.text= "Select R.";
1018         mode= 2;
1019       } else if (button_test(smth,x,y)) {
1020         zt= rez_zt(k0:k1,l0:l1);
1021         if (dimsof(zt)(2)>2 && dimsof(zt)(3)>2) {
1022           rt= rez_rt(k0:k1,l0:l1);
1023           list(,,,2:0)= list(,,,1:-1);
1024           list(,,1,1)= zt;
1025           list(,,2,1)= rt;
1026           zt(2:-1,2:-1)= zt(zcen,zcen)(zcen,zcen);
1027           rt(2:-1,2:-1)= rt(zcen,zcen)(zcen,zcen);
1028           rez_zt(k0:k1,l0:l1)= zt;
1029           rez_rt(k0:k1,l0:l1)= rt;
1030         }
1031       } else if (button_test(eqsp,x,y)) {
1032         zt= rez_zt(k0:k1,l0:l1);
1033         if (dimsof(zt)(2)>2 && dimsof(zt)(3)>2) {
1034           rt= rez_rt(k0:k1,l0:l1);
1035           list(,,,2:0)= list(,,,1:-1);
1036           list(,,1,1)= zt;
1037           list(,,2,1)= rt;
1038           for (ii=0 ; ii<4 ; ii++) {
1039             zt(2:-1,2:-1)= zt(zcen,zcen)(zcen,zcen);
1040             rt(2:-1,2:-1)= rt(zcen,zcen)(zcen,zcen);
1041           }
1042           rez_zt(k0:k1,l0:l1)= zt;
1043           rez_rt(k0:k1,l0:l1)= rt;
1044         }
1045       } else if (abs(_rez_xvp-x)<=_rez_dxvp ||
1046                  abs(_rez_yvp-y)<=_rez_dyvp) {
1047         j= rez_find(m(1), m(2));
1048         kj= (j-1)%kmax + 1;
1049         lj= (j-1)/kmax + 1;
1050         inl= (lj>l0 && lj<l1);
1051         ink= (kj>k0 && kj<k1);
1052         zt= rez_zt(k0:k1,l0:l1);
1053         rt= rez_rt(k0:k1,l0:l1);
1054         if (j>0 && (kj==k0 || kj==k1) && inl) {
1055           list(,,,2:0)= list(,,,1:-1);
1056           list(,,1,1)= zt;
1057           list(,,2,1)= rt;
1058           ds= abs(zt(kj==k0,dif),rt(kj==k0,dif))(-,cum);
1059           ds/= ds(1,0);
1060           rez_zt(k0:k1,l0:l1)= zt(,1) + (zt(,0)-zt(,1))*ds
1061           rez_rt(k0:k1,l0:l1)= rt(,1) + (rt(,0)-rt(,1))*ds
1062         } else if (j>0 && (lj==l0 || lj==l1) && ink) {
1063           list(,,,2:0)= list(,,,1:-1);
1064           list(,,1,1)= zt;
1065           list(,,2,1)= rt;
1066           ds= abs(zt(dif,lj==l0),rt(dif,lj==l0))(cum);
1067           ds/= ds(0);
1068           rez_zt(k0:k1,l0:l1)= zt(1,-,) + (zt(0,-,)-zt(1,-,))*ds
1069           rez_rt(k0:k1,l0:l1)= rt(1,-,) + (rt(0,-,)-rt(1,-,))*ds
1070         } else {
1071           rez_ding;
1072           continue;
1073         }
1074       } else {
1075         rez_ding;
1076         continue;
1077       }
1078     }
1079     rez_plm, !mode, 1;
1080     if (!mode || (jP && jR && kR!=kP && lR!=lP)) {
1081       done.text= "OK";
1082       done.dx= 0.020;
1083     } else {
1084       done.text= "Cancel";
1085       done.dx= 0.033;
1086     }
1087     button_plot, done, lab1, zorp, sets, setp;
1088     if (jP) plg, rez_rt(kP,lP), rez_zt(kP,lP),
1089       marker='P', type=0, legend=string(0);
1090     if (jR) plg, rez_rt(kR,lR), rez_zt(kR,lR),
1091       marker='R', type=0, legend=string(0);
1092     if (jQ) plg, rez_rt(kQ,lQ), rez_zt(kQ,lQ),
1093       marker='Q', type=0, legend=string(0);
1094     if (done.text=="OK") {
1095       if (!jQ) plg, rez_rt(kP,lR), rez_zt(kP,lR),
1096                  marker='Q', type=0, legend=string(0);
1097       plg, rez_rt(kR,lP), rez_zt(kR,lP),
1098         marker='S', type=0, legend=string(0);
1099     }
1100     if (!mode) button_plot, undo, setr, drag, smth, eqsp;
1101     else if (jP || jR) {
1102       text= jP? swrite(format="P=(%ld,%ld)",kP,lP) : "";
1103       if (jR) text+= swrite(format="    R=(%ld,%ld)",kR,lR);
1104       else if (jQ) text+= swrite(format="    Q=(%ld,%ld)",kQ,lQ);
1105       plt, text, 0.35, 0.375;
1106     }
1107   }
1108 
1109   rez_plm, 1;
1110 }
1111 
1112 _rez_zoom= 0n;
1113 
1114 func rez_zoom
1115 /* DOCUMENT rez_zoom
1116      Change limits after setting rez_mesh.
1117 
1118      There are two modes of operation:
1119      (1) P-mode:
1120          Click on a point to magnify or demagnify about that point.
1121          Drag the point to move it to a different position in the
1122          viewport.  The left button zooms in (magnifies by 1.5), the
1123          right button zooms out (demagnifies by 1.5), and the middle
1124          button pans (no magnification change).  If you click just
1125          below or just above the tick marks, only the x coordinate
1126          is changed; clicking just to the left or just to the right
1127          of the viewport changes only the y coordinate.
1128      (2) R-mode:
1129          Left drag out a rectangle to set the limits to that rectangle.
1130          Right drag out a rectangle to cram the entire current viewport
1131          into that rectangle (an analog to zooming out).
1132          Middle drag to pan as in P-mode (the rubber band rectangle is
1133          meaningless in this case).
1134 
1135       Click the [R-mode] (or [P-mode]) button to change modes.
1136 
1137       Click the [OK] button when you are satisfied with the limits.
1138 
1139       Click the [Undo] button to remove the effect of the previous
1140       zoom-click.  Up to 100 successive undo operations are allowed.
1141 
1142       Click the [Polar] button to toggle polar coordinates.  The
1143       vertical axis will be theta, and the horizontal axis radius.
1144       The polar coordinate origin will be at (zt,rt) = (0,0).
1145 
1146       Click the [Next], [Prev], or [First] buttons to focus in on
1147       zones which are bowtied or chevroned.  These zones are marked
1148       by a B or a C, respectively (if rez_mark is set).
1149 
1150    SEE ALSO: rez_mesh
1151  */
1152 {
1153   done= Button(text="OK",x=.203,y=.895,dx=.020,dy=.012);
1154   undo= Button(text="Undo",x=.254,y=.895,dx=.025,dy=.012);
1155   lab2= Button(text="Left=in  Middle=pan  Right=out",
1156                x=.413,y=.895,dx=.128,dy=.012,width=-1);
1157   mode= Button(text=(_rez_zoom?"P-Mode":"R-Mode"),
1158                x=.584,y=.895,dx=.037,dy=.012);
1159 
1160   full= Button(text="Full Mesh",x=.230,y=.375,dx=.046,dy=.012);
1161   polar= Button(text="Polar",x=.307,y=.375,dx=.025,dy=.012);
1162   lab3= Button(text="Go To Bowtie:",
1163                x=.402,y=.375,dx=.040,dy=.012,width=-1);
1164   next= Button(text="Next",x=.486,y=.375,dx=.025,dy=.012);
1165   prev= Button(text="Prev",x=.536,y=.375,dx=.025,dy=.012);
1166   first= Button(text="First",x=.587,y=.375,dx=.026,dy=.012);
1167 
1168   rez_plm, 1;
1169   button_plot, done, undo, lab2, mode, full, polar, lab3, next, prev, first;
1170 
1171   list= array(0.0, 5, 100);  /* keep last 100 limits for undo */
1172   len= 0;
1173   for (;;) {
1174     m= mouse(1, _rez_zoom, "");
1175     if (is_void(m)) { rdline,prompt=""; continue; }
1176     x= m(5);
1177     y= m(6);
1178     if (button_test(done,x,y)) break;
1179     if (button_test(undo,x,y)) {
1180       if (len) {
1181         limits, list(,1);
1182         list(,1:-1)= list(,2:0);
1183         len--;
1184       } else {
1185         rez_ding;
1186         continue;
1187       }
1188     } else if (button_test(mode,x,y)) {
1189       _rez_zoom= !_rez_zoom;
1190       mode.text= (_rez_zoom?"P-Mode":"R-Mode");
1191     } else if (button_test(full,x,y)) {
1192       limits;  redraw;
1193       continue;
1194     } else if (button_test(polar,x,y)) {
1195       rez_toggle;
1196       limits;
1197     } else if (button_test(next,x,y)) {
1198       rez_next;  redraw;
1199       continue;
1200     } else if (button_test(prev,x,y)) {
1201       rez_prev;  redraw;
1202       continue;
1203     } else if (button_test(first,x,y)) {
1204       rez_next, 1;  redraw;
1205       continue;
1206     } else if (abs(_rez_xvp-x)<=_rez_dxvp ||
1207                abs(_rez_yvp-y)<=_rez_dyvp) {
1208       x= m(1);
1209       y= m(2);
1210       x1= m(3);
1211       y1= m(4);
1212       button= long(m(10));
1213       lims= limits();
1214       if (!_rez_zoom || button==2) {  /* point mode */
1215         if (button==1) f= 1.5;
1216         else if (button==2) f= 1.0;
1217         else f= 1.0/1.5;
1218         x0= x - (x1-lims(1))/f;
1219         x1= x - (x1-lims(2))/f;
1220         y0= y - (y1-lims(3))/f;
1221         y1= y - (y1-lims(4))/f;
1222         if (x!=lims(1) && x!=lims(2)) {
1223           if (y!=lims(3) && y!=lims(4)) limits, x0,x1,y0,y1;
1224           else limits, x0,x1;
1225         } else {
1226           if (y!=lims(3) && y!=lims(4)) limits, ,,y0,y1;
1227           else limits, x0,x1,y0,y1;
1228         }
1229         list(,2:0)= list(,1:-1);
1230         list(,1)= lims;
1231         len++;
1232       } else if (x!=x1 && y!=y1) {  /* rectangle mode */
1233         x0= min(x,x1);
1234         x1= max(x,x1);
1235         y0= min(y,y1);
1236         y1= max(y,y1);
1237         if (button!=1) {
1238           f= (lims(2)-lims(1))/(x1-x0);
1239           x0= lims(1) - f*(x0-lims(1));
1240           x1= lims(2) + f*(lims(2)-x1);
1241           f= (lims(4)-lims(3))/(y1-y0);
1242           y0= lims(3) - f*(y0-lims(3));
1243           y1= lims(4) + f*(lims(4)-y1);
1244         }
1245         limits, x0,x1,y0,y1;
1246         list(,2:0)= list(,1:-1);
1247         list(,1)= lims;
1248         len++;
1249       } else {
1250         rez_ding;
1251         continue;
1252       }
1253     }
1254     rez_plm, 0;
1255     button_plot, done, undo, lab2, mode, full, polar, lab3, next, prev, first;
1256   }
1257 }
1258 
1259 func rez_style
1260 {
1261   done= Button(text="OK",x=.203,y=.895,dx=.020,dy=.012);
1262   klin= Button(text="K-line",x=.290,y=.895,dx=.038,dy=.012,width=6.);
1263   llin= Button(text="L-line",x=.366,y=.895,dx=.038,dy=.012);
1264   type= Button(text="Type",x=.476,y=.895,dx=.025,dy=.012,width=6.);
1265   wdth= Button(text="Width",x=.530,y=.895,dx=.029,dy=.012);
1266   colr= Button(text="Color",x=.586,y=.895,dx=.027,dy=.012);
1267 
1268   bar1= ["1", "2", "3", "4", "5", "6", "7", "8"];
1269   bar2= ["bg", "fg", "blk", "wht",
1270          "red", "grn", "blu", "cyn", "mag", "yel"];
1271   bar= array(Button, 10);
1272   bar.dx= bardx= .022;
1273   bar.x= barx= .644;
1274   bar.dy= bardy= .012;
1275   bar.y= .895-(indgen(10)-1)*2.*bardy;
1276   bary= avg(bar.y);
1277 
1278   bar(1:5).text= bar1(1:5);
1279   barn= 5;
1280   bar(rez_kstyle(1)).width= 6.;
1281   change= 1;
1282 
1283   for (;;) {
1284     if (change) {
1285       i= where(bar.width)(1);
1286       if (type.width) {
1287         if (klin.width) rez_kstyle(1)= i;
1288         else rez_lstyle(1)= i;
1289       } else if (wdth.width) {
1290         if (klin.width) rez_kstyle(2)= i;
1291         else rez_lstyle(2)= i;
1292       } else if (colr.width) {
1293         if (klin.width) rez_kstyle(3)= -i;
1294         else rez_lstyle(3)= -i;
1295       }
1296       rez_plm, 0;
1297       button_plot, done, klin, llin, type, wdth, colr, bar(1:barn);
1298       change= 0;
1299     }
1300     m= mouse(0, _rez_zoom, "");
1301     if (is_void(m)) { rdline,prompt=""; continue; }
1302     x= m(5);
1303     y= m(6);
1304     if (button_test(done,x,y)) break;
1305     if (button_test(klin,x,y)) {
1306       if (klin.width) continue;
1307       klin.width= 6.;
1308       llin.width= 0.;
1309       bar.width= 0.;
1310       if (type.width) bar(rez_kstyle(1)).width= 6.;
1311       else if (wdth.width) bar(rez_kstyle(2)).width= 6.;
1312       else if (colr.width) bar(-rez_kstyle(3)).width= 6.;
1313     } else if (button_test(llin,x,y)) {
1314       if (llin.width) continue;
1315       llin.width= 6.;
1316       klin.width= 0.;
1317       bar.width= 0.;
1318       if (type.width) bar(rez_lstyle(1)).width= 6.;
1319       else if (wdth.width) bar(rez_lstyle(2)).width= 6.;
1320       else if (colr.width) bar(-rez_lstyle(3)).width= 6.;
1321     } else if (button_test(type,x,y)) {
1322       if (type.width) continue;
1323       type.width= 6.;
1324       wdth.width= colr.width= 0.;
1325       bar(1:5).text= bar1(1:5);
1326       barn= 5;
1327       bar.width= 0.;
1328       if (klin.width) bar(rez_kstyle(1)).width= 6.;
1329       else bar(rez_lstyle(1)).width= 6.;
1330     } else if (button_test(wdth,x,y)) {
1331       if (wdth.width) continue;
1332       wdth.width= 6.;
1333       type.width= colr.width= 0.;
1334       bar(1:8).text= bar1;
1335       barn= 8;
1336       bar.width= 0.;
1337       if (klin.width) bar(rez_kstyle(2)).width= 6.;
1338       else bar(rez_lstyle(2)).width= 6.;
1339     } else if (button_test(colr,x,y)) {
1340       if (colr.width) continue;
1341       colr.width= 6.;
1342       type.width= wdth.width= 0.;
1343       bar.text= bar2;
1344       barn= 10;
1345       bar.width= 0.;
1346       if (klin.width) bar(-rez_kstyle(3)).width= 6.;
1347       else bar(-rez_lstyle(3)).width= 6.;
1348     } else if (abs(barx-x)<bardx && abs(bary-y)<2.*barn*bardy) {
1349       i= long((bar(1).y+bardy - y)/(2.0*bardy)) + 1;
1350       if (i>0 && i<=barn) {
1351         bar.width= 0.;
1352         bar(i).width= 6.;
1353       } else {
1354         rez_ding;
1355         continue;
1356       }
1357     } else {
1358       rez_ding;
1359       continue;
1360     }
1361     change= 1;
1362   }
1363 }
1364 
1365 extern rez_qrt, rez_qzt, rez_qireg;
1366 /* DOCUMENT rez_qrt, rez_qzt, rez_qireg
1367      are the names of the mesh variables for rez_mesh, "rt", "zt", and
1368      "ireg" by default.  Note that ireg is optional.
1369  */
1370 rez_qzt= "zt";
1371 rez_qrt= "rt";
1372 rez_qireg= "ireg";
1373 
1374 func rez_mesh(rt, zt, ireg, all=, quiet=)
1375 /* DOCUMENT rez_mesh, rt, zt, ireg
1376          or rez_mesh, rt, zt
1377          or rez_mesh, zfile
1378      set mesh for rez_... commands.  If ZFILE is specified, it must be a
1379      binary file containing variables RT, ZT, and (optionally) IREG.
1380    SEE ALSO: rez_all, rez_adjust_mesh
1381  */
1382 {
1383   extern rez_rt0, rez_zt0, rez_ireg0, rez_rt, rez_zt, rez_ireg;
1384   extern rez_mapi;
1385 
1386   if (is_stream(rt)) {
1387     f= rt;
1388     vars= get_vars(f);
1389     ireg= rez_getvar(f,vars, rez_qireg);
1390     zt= rez_getvar(f,vars, rez_qzt);
1391     rt= rez_getvar(f,vars, rez_qrt);
1392   }
1393   if (is_void(ireg)) {
1394     ireg= array(1, dimsof(rt));
1395     ireg(1,)= 0;
1396     ireg(,1)= 0;
1397   }
1398 
1399   rez_rt0= rez_rt= rt;
1400   rez_zt0= rez_zt= zt;
1401   rez_ireg0= rez_ireg= ireg;
1402   if (is_void(zt) || is_void(rt)) return;
1403   rez_ptexist;
1404 
1405   rez_mapi= 0;
1406   if (!quiet) nbow, rez_rt, rez_zt, rez_ireg, all=all;
1407 
1408   rez_plm, 1;
1409 }
1410 
rez_next(which)1411 func rez_next(which)
1412 /* DOCUMENT rez_next
1413      zoom in on next bowtied (or chevroned) zone (after rez_mesh).
1414      With numeric argument, zooms to that bowtie (or chevron).  With
1415      numeric argument 0, zooms to current bowtie (or chevron).
1416    SEE ALSO: rez_prev, rez_mark, rez_drag
1417  */
1418 {
1419   list= where(rez_map==0);
1420   n= where(rez_map==1);
1421   if (!numberof(list)) list= [];
1422   if (!numberof(n)) n= [];
1423   list= grow(list,n);
1424   n= numberof(list);
1425   if (is_void(which)) which= rez_mapi+1;
1426   else if (!which) which= rez_mapi? rez_mapi : 1;
1427   else if (which<0) which= rez_mapi>1? rez_mapi-1 : n+1;
1428   if (!n || which>n) { rez_ding; return; }
1429   local rr, zz;
1430   rez_getrz, list(which);
1431   rn= min(rr);  rx= max(rr);
1432   zn= min(zz);  zx= max(zz);
1433   rr= rx-rn;
1434   zz= zx-zn;
1435   zn-= 0.3*zz;
1436   zx+= 0.3*zz;
1437   rn-= 0.3*rr;
1438   rx+= 0.3*rr;
1439   limits, zn, zx, rn, rx;
1440   rez_mapi= which;
1441 }
1442 
1443 func rez_prev
1444 /* DOCUMENT rez_prev
1445      zoom in on previous bowtied (or chevroned) zone (after rez_mesh).
1446    SEE ALSO: rez_next, rez_mark, rez_drag
1447  */
1448 {
1449   rez_next, -1;
1450 }
1451 
rez_getrz(zlist)1452 func rez_getrz(zlist)
1453 {
1454   extern rr, zz;   /* 2-by-2-by-dimsof(zlist) result */
1455   if (!numberof(zlist)) {
1456     rr= zz= [];
1457     return;
1458   }
1459   dims= dimsof(rez_rt);
1460   kmax= dims(2);
1461   klist= (zlist-1)%(kmax-1);
1462   llist= (zlist-1)/(kmax-1);
1463   list= llist*kmax + klist + 1;  /* lower left corner index */
1464   rr= zz= array(0.0, 2, 2, dimsof(list));
1465   rr(1,1,..)= rez_rt(list);
1466   zz(1,1,..)= rez_zt(list);
1467   rr(2,1,..)= rez_rt(list+1);
1468   zz(2,1,..)= rez_zt(list+1);
1469   rr(1,2,..)= rez_rt(list+kmax);
1470   zz(1,2,..)= rez_zt(list+kmax);
1471   rr(2,2,..)= rez_rt(list+kmax+1);
1472   zz(2,2,..)= rez_zt(list+kmax+1);
1473 }
1474 
1475 func rez_ptexist
1476 {
1477   extern rez_ptx, rez_ptlist, rez_ireg;
1478   rez_ireg(1,)= 0;
1479   rez_ireg(,1)= 0;
1480   d= dimsof(rez_ireg);
1481   ix= d(2);
1482   jx= d(3);
1483   n= numberof(rez_ireg);
1484   ireg= array(0, n+ix+1);
1485   ireg(1:n)= rez_ireg(*);
1486   rez_ptx= array(0, dimsof(rez_ireg));
1487   rez_ptx(*)=
1488     (ireg(1:n) | ireg(2:n+1) | ireg(ix+1:n+ix) | ireg(ix+2:n+ix+1));
1489   rez_ptlist= where(rez_ptx);
1490 }
1491 
1492 extern _rez_center;
1493 
rez_find(x,y)1494 func rez_find(x, y)
1495 {
1496   extern _rez_center;
1497   d= abs(rez_zt-x, rez_rt-y)(rez_ptlist);
1498   j= d(mnx);
1499   d0= d(j);
1500   j0= rez_ptlist(j);
1501   j= where(!(d-d0));  /* detect center points */
1502   if (numberof(j)>1) _rez_center= rez_ptlist(j);
1503   else _rez_center= [];
1504   return j0;
1505 }
1506 
rez_getvar(f,vars,name)1507 func rez_getvar(f, vars, name)
1508 {
1509   v= vars(2);
1510   if (v && anyof(*v == name)) return get_member(f,name);
1511   v= vars(1);
1512   if (v && anyof(*v == name)) return get_member(f,name);
1513   return [];
1514 }
1515 
rez_range(x)1516 func rez_range(x) { return x; }  /* parser quirk */
1517 
1518 func rez_ding
1519 {
1520   write, format="%s", "\a\a";
1521 }
1522 
rez_solve(ss,nn)1523 func rez_solve(ss, nn)
1524 /* xxDOCUMENT adapted from gseries_r(s, n) in series.i
1525      returns the ratio r of the finite geometric series, given the sum s:
1526         1 + r + r^2 + r^3 + ... + r^(nn-1) = ss,
1527         or (r^nn-1)/(r-1) = ss
1528 
1529      Altered to solve only nn>0.0, but allows any real nn.
1530  */
1531 {
1532   /* compute an approximate result which has exact values and
1533      derivatives at s==1, s==n, and s->infinity --
1534      different approximations apply for s>n and s<n */
1535   if (nn==2) return ss-1.0;
1536   if (ss>nn) {
1537     pow= 1.0/(nn-1.0);
1538     npow= nn^pow - 1.0;
1539     n2r= 1.0/(nn-2.0);
1540     A= (2.0-nn*npow)*n2r;
1541     B= (2.0*npow-nn*pow)*nn*n2r;
1542     r= ss^pow - pow + A*(nn/ss)^pow + B/ss;
1543   } else {
1544     sn= (ss-1.0)/(nn-1.0);
1545     n2r= 1.0/(nn*nn);
1546     r= 1.0 - 1.0/ss + n2r*sn*sn*(nn+1.0 - sn);
1547   }
1548 
1549   /* Polish the approximation using Newton-Raphson iterations.  */
1550   if (ss!=nn) {
1551     for (;;) {
1552       rr= r-1.0;
1553       rn= r^(nn-1);
1554       rrss= rr*ss;
1555       delta= rrss - (r*rn-1.0);
1556       if (abs(delta)<=1.e-9*abs(rrss)) break;
1557       r+= delta/(nn*rn-ss);
1558     }
1559     /* try to get it to machine precision */
1560     if (delta) r+= delta/(nn*rn-ss);
1561   }
1562 
1563   return r;
1564 }
1565 
1566 func rez_test
1567 {
1568   extern rez_rt, rez_zt;
1569   x= span(0,1,10)(,-:1:7);  y= span(0,.5,7)(-:1:10,);
1570   rez_mesh, x+y, x-y+.5;
1571 }
1572 
1573 if (!is_void(rez_load_hook)) include, rez_load_hook;
1574