1 /*
2 * $Id: plwf.i,v 1.1 2005-09-18 22:06:04 dhmunro Exp $
3 * Simple "painter's algorithm"-class routine for making 3-D wire frames
4 * and related models.
5 */
6 /* Copyright (c) 2005, The Regents of the University of California.
7 * All rights reserved.
8 * This file is part of yorick (http://yorick.sourceforge.net).
9 * Read the accompanying LICENSE file for details.
10 */
11
12 require, "pl3d.i";
13
14 func plwf(z,y,x, fill=,shade=,edges=,ecolor=,ewidth=,cull=,scale=,cmax=)
15 /* DOCUMENT plwf, z
16 or plwf, z, y,x
17
18 plots a 3-D wire frame of the given Z array, which must have the
19 same dimensions as the mesh (X, Y). If X and Y are not given, they
20 default to the first and second indices of Z, respectively.
21 The drawing order of the zones is determined by a simple "painter's
22 algorithm", which works fairly well if the mesh is reasonably near
23 rectilinear, but can fail even then if the viewpoint is chosen to
24 produce extreme fisheye perspective effects. Look at the resulting
25 plot carefully to be sure the algorithm has correctly rendered the
26 model in each case.
27
28 KEYWORDS: fill -- optional colors to use (default is to make zones
29 have background color), same dimension options as
30 for z argument to plf function
31 shade -- set non-zero to compute shading from current
32 3D lighting sources
33 edges -- default is 1 (draw edges), but if you provide fill
34 colors, you may set to 0 to supress the edges
35 ecolor, ewidth -- color and width of edges
36 cull -- default is 1 (cull back surfaces), but if you want
37 to see the "underside" of the model, set to 0
38 scale -- by default, Z is scaled to "reasonable" maximum
39 and minimum values related to the scale of (X,Y).
40 This keyword alters the default scaling factor, in
41 the sense that scale=2.0 will produce twice the
42 Z-relief of the default scale=1.0.
43 cmax -- the ambient= keyword in light3 can be used to
44 control how dark the darkest surface is; use this
45 to control how light the lightest surface is
46 the lightwf routine can change this parameter
47 interactively
48
49 SEE ALSO: lightwf, plm, plf, orient3, light3, window3, limit3
50 */
51 {
52 if (_draw3) {
53 xyz= _nxt(z);
54 fill= _nxt(z);
55 shade= _nxt(z);
56 edges= _nxt(z);
57 ecolor= _nxt(z);
58 ewidth= _nxt(z);
59 cull= _nxt(z);
60 cmax= _nxt(z);
61
62 get3_xy, xyz, x, y, z, 1;
63
64 /* rotate (x,y,0) into on-screen orientation to determine order
65 * just use four corners for this */
66 nx= dimsof(x);
67 ny= nx(3);
68 nx= nx(2);
69 xyzc= xyz(,1:nx:nx-1,1:ny:ny-1);
70 xyzc(3,,)= 0.0;
71 get3_xy, xyzc, xc, yc, zc, 1;
72
73 /* compute mean i-edge and j-edge vector z-components */
74 iedge= avg(zc(0,)-zc(1,));
75 jedge= avg(zc(,0)-zc(,1));
76
77 /* compute shading if necessary */
78 if (shade) {
79 xyz(1,,)= x;
80 xyz(2,,)= y;
81 xyz(3,,)= z;
82 fill= get3_light(xyz);
83 }
84
85 /* The order either requires a transpose or not, reversal of the
86 order of the first dimension or not, and reversal of the order
87 of the second dimension or not. */
88
89 /* The direction with the minimum magnitude average z-component must
90 vary fastest in the painting order. If this is the j-direction,
91 a transpose will be required to make this the i-direction. */
92 if (abs(jedge)<abs(iedge)) {
93 tmp= iedge; iedge= jedge; jedge= tmp;
94 x= transpose(x);
95 y= transpose(y);
96 if (!is_void(fill)) fill= transpose(fill);
97 }
98
99 /* Zones must be drawn from back to front, which means that the
100 average z-component of the edge vectors must be positive. This
101 can be arranged by reversing the order of the elements if
102 necessary. */
103 if (iedge<0.0) {
104 x= x(::-1,);
105 y= y(::-1,);
106 if (!is_void(fill)) fill= fill(::-1,);
107 }
108 if (jedge<0.0) {
109 x= x(,::-1);
110 y= y(,::-1);
111 if (!is_void(fill)) fill= fill(,::-1);
112 }
113
114 plf, fill, y,x, edges=edges,ecolor=ecolor,ewidth=ewidth,
115 cmin=0.0,cmax=cmax,legend=string(0);
116 return;
117 }
118
119 xyz= xyz_wf(z, y, x, scale, scale=scale);
120
121 if (is_void(edges)) edges= 1;
122 if (is_void(shade)) shade= 0;
123 else if (!is_void(fill))
124 error, "specify either fill or shade, not both";
125
126 clear3;
127 limit3, scale;
128 set3_object, plwf,
129 _lst(xyz, fill, shade, edges, ecolor, ewidth, cull, cmax);
130 }
131
lightwf(cmax)132 func lightwf(cmax)
133 /* DOCUMENT lightwf, cmax
134 Sets the cmax= parameter interactively, assuming the current
135 3D display list contains the result of a previous plwf call.
136 This changes the color of the brightest surface in the picture.
137 The darkest surface color can be controlled using the ambient=
138 keyword to light3.
139 SEE ALSO: plwf, light3
140 */
141 {
142 list= _cdr(_draw3_list, _draw3_n);
143 if (_car(list)!=plwf) error, "current 3D display list is not a plwf";
144 _undo3_set, lightwf, _car(_car(list,2), 8, cmax);
145 }
146
147 /* The function which scales the "topography" of z(x,y) is
148 * potentially useful apart from plwf.
149 * For example, the xyz array used by plwf can be converted from
150 * a quadrilateral mesh plotted using plf to a polygon list plotted
151 * using plfp like this:
152 * xyz= xyz_wf(z,y,x,lims,scale=scale);
153 * ni= dimsof(z)(2);
154 * nj= dimsof(z)(3);
155 * list= indgen(1:ni-1)+ni*indgen(0:nj-2)(-,);
156 * xyz= xyz(,([0,1,ni+1,ni]+list(-,))(*));
157 * nxyz= array(4, (ni-1)*(nj-1));
158 * ...
159 * limit3, lims;
160 */
161 func xyz_wf(z, y, x, &lims, scale=)
162 {
163 if (min(dimsof(z))<2) error, "impossible dimensions for z array";
164 if (is_void(y) || is_void(x)) {
165 if (!is_void(y) || !is_void(x)) error, "either give y,x both or neither";
166 nx= dimsof(z)(2);
167 ny= dimsof(z)(3);
168 x= span(1,nx,nx)(,-:1:ny);
169 y= span(1,ny,ny)(-:1:nx,);
170 } else if (anyof(dimsof(x)!=dimsof(z)) ||
171 anyof(dimsof(x)!=dimsof(z))) {
172 error, "x, y, and z must all have same dimensions";
173 }
174
175 lims= array(0., 3,3);
176 lims(1:2,1)= xnx= _wf_safe(x);
177 lims(1:2,2)= ynx= _wf_safe(y);
178 lims(1:2,3)= _wf_safe(z);
179 lims(3,1)= xnx(ptp);
180 lims(3,2)= ynx(ptp);
181 xyscl= double(max(xnx(ptp),ynx(ptp)));
182 if (!is_void(scale)) xyscl*= scale;
183 lims(3,3)= 0.5*xyscl;
184
185 xyz= array(0.0, 3,dimsof(z));
186 xyz(1,,)= x;
187 xyz(2,,)= y;
188 xyz(3,,)= z;
189
190 return xyz;
191 }
192
_wf_safe(a)193 func _wf_safe(a)
194 {
195 mx= max(a);
196 mn= min(a);
197 if (mx==mn) {
198 d= mn? 0.01*abs(mn) : 0.01;
199 mn-= d;
200 mx+= d;
201 }
202 return [mn,mx];
203 }
204