# HG changeset patch # User David Bateman # Date 1239459961 -7200 # Node ID 22ae6b3411a769d62f66f196473336440194404a # Parent 978c863bc8e5d983cfad9329742a8b941b4879fb Add isocolor, isonormals and isosurface functions (For Martin Helm). Add 3D filled triangular patches and the trisurf function diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-04-11 David Bateman + + * NEWS: Add new graphics functions. + 2009-04-05 John W. Eaton * configure.in: Use AC_USE_SYSTEM_EXTENSIONS instead of diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -22,15 +22,16 @@ ** New graphics functions: - addlistener diffuse ezsurfc plotmatrix - addproperty ezcontour findall refresh - allchild ezcontourf gcbf refreshdata - available_backends ezmesh gcbo specular - backend ezmeshc ginput surfl - cla ezplot gtext waitforbuttonpress - clabel ezplot3 intwarning - comet ezpolar ishghandle - dellistener ezsurf linkprop + addlistener ezcontour gcbo refresh + addproperty ezcontourf ginput refreshdata + allchild ezmesh gtext specular + available_backends ezmeshc intwarning surfl + backend ezplot ishghandle trisurf + cla ezplot3 isocolors waitforbuttonpress + clabel ezpolar isonormals + comet ezsurf isosurface + dellistener findall linkprop + diffuse gcbf plotmatrix ** New experimental OpenGL/FLTK based plotting system. diff --git a/doc/ChangeLog b/doc/ChangeLog --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2009-04-11 David Bateman + + * interpreter/contributors.in: Add Martin Helm. + 2009-04-06 John W. Eaton * texinfo.tex: Prefer PDF image files if generating PDF output. diff --git a/doc/interpreter/contributors.in b/doc/interpreter/contributors.in --- a/doc/interpreter/contributors.in +++ b/doc/interpreter/contributors.in @@ -70,6 +70,7 @@ Soren Hauberg Dave Hawthorne Daniel Heiserer +Martin Helm Yozo Hida Ryan Hinton Roman Hodek diff --git a/scripts/ChangeLog b/scripts/ChangeLog --- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,19 @@ +2009-04-11 David Bateman + + * geometry/trisurf.m: New file. + * geometry/Makefile.in (SOURCES): Add it here. + * geometry/trimesh.m: Convert to using 3D patches. + * plot/__go_draw_axes__.m: Allow 3D filled triangular patches. + * plot/__patch__.m: Rewrite to allow update of dependent variables + with listener functions amongst themselves. + * plot/patch.m: Add 3D demo. Update the documentation. + +2009-04-11 Martin Helm + + * plot/__interp_cube__.m, plot/__marching_cube__.m, isocolors.m, + isonnormals.m, isosurface.m: New files. + * plot/Makefile.in (SOURCES): Add them here. + 2009-04-11 Jaroslav Hajek * set/intersect.m: Add missing branch. diff --git a/scripts/geometry/Makefile.in b/scripts/geometry/Makefile.in --- a/scripts/geometry/Makefile.in +++ b/scripts/geometry/Makefile.in @@ -46,6 +46,7 @@ rectint.m \ trimesh.m \ triplot.m \ + trisurf.m \ tsearchn.m \ voronoi.m \ voronoin.m diff --git a/scripts/geometry/trimesh.m b/scripts/geometry/trimesh.m --- a/scripts/geometry/trimesh.m +++ b/scripts/geometry/trimesh.m @@ -38,27 +38,29 @@ elseif (ischar (z)) triplot (tri, x, y, z, varargin{:}); else - idx = tri(:, [1,2,3,1]).'; - nt = size (tri, 1); - ## FIXME We should really use patch instead of plot3, but we don't - ## have a patch function, and probably won't in 3D that works with - ## gnuplot + newplot (); if (nargout > 0) - h = plot3 ([x(idx); NaN*ones(1, nt)](:), - [y(idx); NaN*ones(1, nt)](:), - [z(idx); NaN*ones(1, nt)](:), varargin{:}); + h = patch ("Vertices", [x(:), y(:), z(:)], "Faces", tri, + "FaceColor", "none", "EdgeColor", __next_line_color__(), + varargin{:}); else - plot3 ([x(idx); NaN*ones(1, nt)](:), - [y(idx); NaN*ones(1, nt)](:), - [z(idx); NaN*ones(1, nt)](:), varargin{:}); + patch ("Vertices", [x(:), y(:), z(:)], "Faces", tri, + "FaceColor", "none", "EdgeColor", __next_line_color__(), + varargin{:}); + endif + + if (! ishold ()) + set (gca(), "view", [-37.5, 30], + "xgrid", "on", "ygrid", "on", "zgrid", "on"); endif endif endfunction %!demo +%! N = 10; %! rand ('state', 10) -%! x = 3 - 6 * rand (1, 50); -%! y = 3 - 6 * rand (1, 50); +%! x = 3 - 6 * rand (N, N); +%! y = 3 - 6 * rand (N, N); %! z = peaks (x, y); -%! tri = delaunay (x, y); -%! trimesh (tri, x, y, z); +%! tri = delaunay (x(:), y(:)); +%! trimesh (tri, x(:), y(:), z(:)); diff --git a/scripts/geometry/trisurf.m b/scripts/geometry/trisurf.m new file mode 100644 --- /dev/null +++ b/scripts/geometry/trisurf.m @@ -0,0 +1,75 @@ +## Copyright (C) 2007, 2008 David Bateman +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {Function File} {} trisurf (@var{tri}, @var{x}, @var{y}, @var{z}) +## @deftypefnx {Function File} {@var{h} =} trisurf (@dots{}) +## Plot a triangular surface in 3D. The variable @var{tri} is the triangular +## meshing of the points @code{(@var{x}, @var{y})} which is returned +## from @code{delaunay}. The variable @var{z} is value at the point +## @code{(@var{x}, @var{y})}. The output argument @var{h} is the graphic +## handle to the plot. +## @seealso{triplot, delaunay3} +## @end deftypefn + +function h = trisurf (tri, x, y, z, varargin) + + if (nargin < 3) + print_usage (); + endif + + if (nargin == 3) + triplot (tri, x, y); + elseif (ischar (z)) + triplot (tri, x, y, z, varargin{:}); + else + if (nargin > 4 && isnumeric (varargin{1})) + c = varargin{1}; + varargin(1) = []; + else + c = z; + endif + + newplot (); + if (nargout > 0) + h = patch ("Faces", tri, "Vertices", [x(:), y(:), z(:)], + "FaceVertexCData", reshape (c, numel (c), 1), + "FaceColor", "flat", "EdgeColor", "none", + varargin{:}); + else + patch ("Faces", tri, "Vertices", [x(:), y(:), z(:)], + "FaceVertexCData", reshape (c, numel (c), 1), + "FaceColor", "flat", "EdgeColor", "none", + varargin{:}); + endif + + if (! ishold ()) + set (gca(), "view", [-37.5, 30], + "xgrid", "on", "ygrid", "on", "zgrid", "on"); + endif + endif +endfunction + +%!demo +%! N = 10; +%! rand ('state', 10) +%! x = 3 - 6 * rand (N, N); +%! y = 3 - 6 * rand (N, N); +%! z = peaks (x, y); +%! tri = delaunay (x(:), y(:)); +%! trisurf (tri, x(:), y(:), z(:)); diff --git a/scripts/plot/Makefile.in b/scripts/plot/Makefile.in --- a/scripts/plot/Makefile.in +++ b/scripts/plot/Makefile.in @@ -54,7 +54,9 @@ __go_draw_figure__.m \ __gnuplot_ginput__.m \ __gnuplot_version__.m \ + __interp_cube__.m \ __line__.m \ + __marching_cube__.m \ __next_line_color__.m \ __patch__.m \ __plr1__.m \ @@ -131,6 +133,9 @@ isfigure.m \ ishghandle.m \ ishold.m \ + isocolors.m \ + isonormals.m \ + isosurface.m \ legend.m \ line.m \ linkprop.m \ diff --git a/scripts/plot/__go_draw_axes__.m b/scripts/plot/__go_draw_axes__.m --- a/scripts/plot/__go_draw_axes__.m +++ b/scripts/plot/__go_draw_axes__.m @@ -318,6 +318,7 @@ if (! cautoscale && clim(1) == clim(2)) clim(2)++; endif + addedcmap = []; [view_cmd, view_fcn, view_zoom] = image_viewer (); use_gnuplot_for_images = (ischar (view_fcn) @@ -357,6 +358,7 @@ is_image_data(data_idx) = true; parametric(data_idx) = false; have_cdata(data_idx) = false; + have_3d_patch(data_idx) = false; [y_dim, x_dim] = size (img_data(:,:,1)); if (x_dim > 1) @@ -406,6 +408,8 @@ is_image_data(data_idx) = false; parametric(data_idx) = true; have_cdata(data_idx) = false; + have_3d_patch(data_idx) = false; + if (isempty (obj.keylabel)) titlespec{data_idx} = "title \"\""; else @@ -517,6 +521,7 @@ cdat = []; endif + data_3d_idx = NaN; for i = 1:nc xcol = obj.xdata(:,i); ycol = obj.ydata(:,i); @@ -533,22 +538,42 @@ if (strncmp (obj.facecolor, "none", 4)) hidden_removal = false; else + if (isnan (hidden_removal)) hidden_removal = true; endif if (nd == 3) - error ("gnuplot (as of v4.2) only supports 2D filled patches"); + if (numel (xcol) > 3) + error ("gnuplot (as of v4.2) only supports 3D filled triangular patches"); + else + if (isnan (data_3d_idx)) + data_idx++; + data_3d_idx = data_idx; + is_image_data(data_idx) = false; + parametric(data_idx) = false; + have_cdata(data_idx) = true; + have_3d_patch(data_idx) = true; + withclause{data_3d_idx} = sprintf ("with pm3d"); + usingclause{data_3d_idx} = "using 1:2:3:4"; + data{data_3d_idx} = []; + endif + local_idx = data_3d_idx; + ccdat = NaN; + endif + else + data_idx++; + local_idx = data_idx; + is_image_data(data_idx) = false; + parametric(data_idx) = false; + have_cdata(data_idx) = false; + have_3d_patch(data_idx) = false; endif - data_idx++; - is_image_data(data_idx) = false; - parametric(data_idx) = false; - have_cdata(data_idx) = false; if (i > 1 || isempty (obj.keylabel)) - titlespec{data_idx} = "title \"\""; + titlespec{local_idx} = "title \"\""; else tmp = undo_string_escapes (__maybe_munge_text__ (enhanced, obj, "keylabel")); - titlespec{data_idx} = cstrcat ("title \"", tmp, "\""); + titlespec{local_idx} = cstrcat ("title \"", tmp, "\""); endif if (isfield (obj, "facecolor")) if ((strncmp (obj.facecolor, "flat", 4) @@ -572,6 +597,8 @@ if (strncmp (obj.facecolor, "flat", 4)) if (numel(ccol) == 3) color = ccol; + elseif (nd == 3 && numel (xcol) == 3) + ccdat = ccol * ones (3,1); else r = 1 + round ((size (cmap, 1) - 1) * (ccol - clim(1))/(clim(2) - clim(1))); @@ -579,10 +606,22 @@ color = cmap(r, :); endif elseif (strncmp (obj.facecolor, "interp", 6)) - warning ("\"interp\" not supported, using 1st entry of cdata"); - r = 1 + round ((size (cmap, 1) - 1) * ccol(1)); - r = max (1, min (r, size (cmap, 1))); - color = cmap(r,:); + if (nd == 3 && numel (xcol) == 3) + ccdat = ccol; + if (! isvector (ccdat)) + tmp = rows(cmap) + rows(addedcmap) + ... + [1 : rows(ccdat)]; + addedcmap = [addedcmap; ccdat]; + ccdat = tmp(:); + else + ccdat = ccdat(:); + endif + else + warning ("\"interp\" not supported, using 1st entry of cdata"); + r = 1 + round ((size (cmap, 1) - 1) * ccol(1)); + r = max (1, min (r, size (cmap, 1))); + color = cmap(r,:); + endif endif elseif (isnumeric (obj.facecolor)) color = obj.facecolor; @@ -593,21 +632,32 @@ color = [0, 1, 0]; endif - if (mono) - colorspec = ""; - elseif (__gnuplot_has_feature__ ("transparent_patches") - && isscalar (obj.facealpha)) - colorspec = sprintf ("lc rgb \"#%02x%02x%02x\" fillstyle transparent solid %f", - round (255*color), obj.facealpha); + if (nd == 3 && numel (xcol) == 3) + if (isnan (ccdat)) + ccdat = (rows (cmap) + rows(addedcmap) + 1) * ones(3, 1); + addedcmap = [addedcmap; reshape(color, 1, 3)]; + endif + data{data_3d_idx} = [data{data_3d_idx}, ... + [[xcol; xcol(end)], [ycol; ycol(end)], ... + [zcol; zcol(end)], [ccdat; ccdat(end)]]']; else - colorspec = sprintf ("lc rgb \"#%02x%02x%02x\"", - round (255*color)); + if (mono) + colorspec = ""; + elseif (__gnuplot_has_feature__ ("transparent_patches") + && isscalar (obj.facealpha)) + colorspec = sprintf ("lc rgb \"#%02x%02x%02x\" fillstyle transparent solid %f", + round (255*color), obj.facealpha); + else + colorspec = sprintf ("lc rgb \"#%02x%02x%02x\"", + round (255*color)); + endif + + withclause{data_idx} = sprintf ("with filledcurve %s", + colorspec); + data{data_idx} = [xcol, ycol]'; + usingclause{data_idx} = sprintf ("record=%d using ($1):($2)", + numel (xcol)); endif - withclause{data_idx} = sprintf ("with filledcurve %s", - colorspec); - data{data_idx} = [xcol, ycol]'; - usingclause{data_idx} = sprintf ("record=%d using ($1):($2)", - numel (xcol)); endif endif @@ -618,6 +668,7 @@ is_image_data(data_idx) = false; parametric(data_idx) = false; have_cdata(data_idx) = false; + have_3d_patch(data_idx) = false; titlespec{data_idx} = "title \"\""; usingclause{data_idx} = sprintf ("record=%d", numel (obj.xdata)); @@ -793,6 +844,7 @@ is_image_data(data_idx) = false; parametric(data_idx) = false; have_cdata(data_idx) = true; + have_3d_patch(data_idx) = false; [style, typ, with] = do_linestyle_command (obj, data_idx, mono, plot_stream); if (isempty (obj.keylabel)) @@ -1037,12 +1089,22 @@ cmap = parent_figure_obj.colormap; cmap_sz = rows(cmap); - if (! any (isinf (clim))) if (truecolor || ! cdatadirect) - fprintf (plot_stream, "set cbrange [%g:%g];\n", clim); + if (rows(addedcmap) > 0) + for i = 1:data_idx + if (have_3d_patch(i)) + data{i}(end,:) = clim(2) * (data{i}(end, :) - 0.5) / cmap_sz; + endif + endfor + fprintf (plot_stream, "set cbrange [%g:%g];\n", clim(1), clim(2) * + (cmap_sz + rows(addedcmap)) / cmap_sz); + else + fprintf (plot_stream, "set cbrange [%g:%g];\n", clim); + endif else - fprintf (plot_stream, "set cbrange [1:%d];\n", cmap_sz); + fprintf (plot_stream, "set cbrange [1:%d];\n", cmap_sz + + rows (addedcmap)); endif endif @@ -1160,6 +1222,8 @@ endfor endif + cmap = [cmap; addedcmap]; + cmap_sz = cmap_sz + rows(addedcmap); if (length(cmap) > 0) fprintf (plot_stream, "set palette positive color model RGB maxcolors %i;\n", @@ -1190,7 +1254,11 @@ fprintf (plot_stream, "set view %.15g, %.15g;\n", rot_x, rot_z); endif endif - if (is_image_data (1)) + if (have_3d_patch (1)) + fputs (plot_stream, "set pm3d depthorder\n"); + fprintf (plot_stream, "%s \"-\" %s %s %s \\\n", plot_cmd, + usingclause{1}, titlespec{1}, withclause{1}); + elseif (is_image_data (1)) fprintf (plot_stream, "%s \"-\" %s %s %s \\\n", plot_cmd, usingclause{1}, titlespec{1}, withclause{1}); else @@ -1198,8 +1266,11 @@ usingclause{1}, titlespec{1}, withclause{1}); endif for i = 2:data_idx - if (is_image_data (i)) - fprintf (plot_stream, "%s \"-\" %s %s %s \\\n", plot_cmd, + if (have_3d_patch (i)) + fprintf (plot_stream, ", \"-\" %s %s %s \\\n", + usingclause{i}, titlespec{i}, withclause{i}); + elseif (is_image_data (i)) + fprintf (plot_stream, "%s \"-\" %s %s %s \\\n", plot_cmd, usingclause{i}, titlespec{i}, withclause{i}); else fprintf (plot_stream, ", \"-\" binary format='%%float64' %s %s %s \\\n", @@ -1208,7 +1279,21 @@ endfor fputs (plot_stream, ";\n"); for i = 1:data_idx - if (is_image_data(i)) + if (have_3d_patch (i)) + ## Can't write 3d patch data as binary as can't plot more than + ## a single patch at a time and have to plot all patches together + ## so that the gnuplot depth ordering is done correctly + for j = 1 : 4 : columns(data{i}) + if (j != 1) + fputs (plot_stream, "\n\n"); + endif + fprintf (plot_stream, "%.15g %.15g %.15g %.15g\n", data{i}(:,j).'); + fprintf (plot_stream, "%.15g %.15g %.15g %.15g\n\n", data{i}(:,j+1).'); + fprintf (plot_stream, "%.15g %.15g %.15g %.15g\n", data{i}(:,j+2).'); + fprintf (plot_stream, "%.15g %.15g %.15g %.15g\n", data{i}(:,j+3).'); + endfor + fputs (plot_stream, "e\n"); + elseif (is_image_data(i)) fwrite (plot_stream, data{i}, "float32"); else __gnuplot_write_data__ (plot_stream, data{i}, nd, parametric(i), diff --git a/scripts/plot/__interp_cube__.m b/scripts/plot/__interp_cube__.m new file mode 100644 --- /dev/null +++ b/scripts/plot/__interp_cube__.m @@ -0,0 +1,181 @@ +## Copyright (C) 2009 Martin Helm +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see http://www.gnu.org/licenses/gpl.html. +## +## Author: Martin Helm + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{vxyz}, @var{idx}, @var{frac}] =} __interp_cube__ (@var{x}, @var{y}, @var{z}, @var{val}, @var{v}) +## Undocumented internal function. +## @end deftypefn + +function [Vxyz, idx, frac] = __interp_cube__(x, y, z, val, v, req = "values" ) + if (ismatrix (x) && ndims (x) == 3 && ismatrix (y) && ndims (y) == 3 ... + && ismatrix (z) && ndims (z) == 3 && size_equal (x, y, z, val)) + x = squeeze (x(1,:,1))(:); + y = squeeze (y(:,1,1))(:); + z = squeeze (z(1,1,:))(:); + elseif (isvector (x) && isvector (y) && isvector (z) ) + x = x(:); + y = y(:); + z = z(:); + else + error("x, y, z have wrong dimensions"); + endif + if (size (val) != [length(x), length(y), length(z)]) + error ("val has wrong dimensions"); + endif + if (size (v, 2) != 3) + error ( "v has to be N*3 matrix"); + endif + if (!ischar (req)) + error ("Invalid request parameter use 'values', 'normals' or 'normals8'"); + endif + if (isempty (v)) + Vxyz = idx = frac = []; + return + endif + + switch req + case "values" + [Vxyz, idx, frac] = interp_cube_trilin (x, y, z, val, v); + case "normals" + [idx, frac] = cube_idx (x, y, z, v); + + dx = x(2:end) - x(1:end-1); + dy = y(2:end) - y(1:end-1); + dz = z(2:end) - z(1:end-1); + dx = 0.5 .* [dx;dx(end)](idx(:,2)); + dy = 0.5 .* [dy;dy(end)](idx(:,1)); + dz = 0.5 .* [dz;dz(end)](idx(:,3)); + + p000 = [v(:, 1) - dx, v(:, 2) - dy, v(:, 3) - dz]; + p100 = [v(:, 1) + dx, v(:, 2) - dy, v(:, 3) - dz]; + p010 = [v(:, 1) - dx, v(:, 2) + dy, v(:, 3) - dz]; + p001 = [v(:, 1) - dx, v(:, 2) - dy, v(:, 3) + dz]; + p011 = [v(:, 1) - dx, v(:, 2) + dy, v(:, 3) + dz]; + p101 = [v(:, 1) + dx, v(:, 2) - dy, v(:, 3) + dz]; + p110 = [v(:, 1) + dx, v(:, 2) + dy, v(:, 3) - dz]; + p111 = [v(:, 1) + dx, v(:, 2) + dy, v(:, 3) + dz]; + + v000 = interp_cube_trilin (x, y, z, val, p000); + v100 = interp_cube_trilin (x, y, z, val, p100); + v010 = interp_cube_trilin (x, y, z, val, p010); + v001 = interp_cube_trilin (x, y, z, val, p001); + v011 = interp_cube_trilin (x, y, z, val, p011); + v101 = interp_cube_trilin (x, y, z, val, p101); + v110 = interp_cube_trilin (x, y, z, val, p110); + v111 = interp_cube_trilin (x, y, z, val, p111); + + Dx = -v000 .+ v100 .- v010 .- v001 .- v011 .+ v101 .+ v110 .+ v111; + Dy = -v000 .- v100 .+ v010 .- v001 .+ v011 .- v101 .+ v110 .+ v111; + Dz = -v000 .- v100 .- v010 .+ v001 .+ v011 .+ v101 .- v110 .+ v111; + Vxyz = 0.5 .* [Dx./dx, Dy./dy, Dz./dz]; + case "normals8" + [idx, frac] = cube_idx (x, y, z, v); + + dx = x(2:end) - x(1:end-1); + dy = y(2:end) - y(1:end-1); + dz = z(2:end) - z(1:end-1); + dx = [dx;dx(end)](idx(:,2)); + dy = [dy;dy(end)](idx(:,1)); + dz = [dz;dz(end)](idx(:,3)); + [Dx, Dy, Dz, idx, frac] = interp_cube_trilin_grad (x, y, z, val, v); + Vxyz = [Dx./dx, Dy./dy, Dz./dz]; + otherwise + error ("Invalid request type '%s', use 'values', 'normals' or 'normals8'", req); + endswitch +endfunction + +function [Vxyz, idx, frac] = interp_cube_trilin(x, y, z, val, v) + [idx, frac] = cube_idx (x(:), y(:), z(:), v); + sval = size (val); + i000 = sub2ind (sval, idx(:, 1), idx(:, 2), idx(:, 3)); + i100 = sub2ind (sval, idx(:, 1)+1, idx(:, 2), idx(:, 3)); + i010 = sub2ind (sval, idx(:, 1), idx(:, 2)+1, idx(:, 3)); + i001 = sub2ind (sval, idx(:, 1), idx(:, 2), idx(:, 3)+1); + i101 = sub2ind (sval, idx(:, 1)+1, idx(:, 2), idx(:, 3)+1); + i011 = sub2ind (sval, idx(:, 1), idx(:, 2)+1, idx(:, 3)+1); + i110 = sub2ind (sval, idx(:, 1)+1, idx(:, 2)+1, idx(:, 3)); + i111 = sub2ind (sval, idx(:, 1)+1, idx(:, 2)+1, idx(:, 3)+1 ); + Bx = frac(:, 1); + By = frac(:, 2); + Bz = frac(:, 3); + Vxyz = ... + val( i000 ) .* (1 .- Bx) .* (1 .- By) .* (1 .- Bz) .+ ... + val( i100 ) .* Bx .* (1 .- By) .* (1 .- Bz) .+ ... + val( i010 ) .* (1 .- Bx) .* By .* (1 .- Bz) .+ ... + val( i001 ) .* (1 .- Bx) .* (1 .- By) .* Bz .+ ... + val( i011 ) .* (1 .- Bx) .* By .* Bz .+ ... + val( i101 ) .* Bx .* (1 .- By) .* Bz .+ ... + val( i110 ) .* Bx .* By .* (1 .- Bz) .+ ... + val( i111 ) .* Bx .* By .* Bz; +endfunction + +function [Dx, Dy, Dz, idx, frac] = interp_cube_trilin_grad(x, y, z, val, v) + [idx, frac] = cube_idx (x(:), y(:), z(:), v); + sval = size (val); + i000 = sub2ind (sval, idx(:, 1), idx(:, 2), idx(:, 3)); + i100 = sub2ind (sval, idx(:, 1)+1, idx(:, 2), idx(:, 3)); + i010 = sub2ind (sval, idx(:, 1), idx(:, 2)+1, idx(:, 3)); + i001 = sub2ind (sval, idx(:, 1), idx(:, 2), idx(:, 3)+1); + i101 = sub2ind (sval, idx(:, 1)+1, idx(:, 2), idx(:, 3)+1); + i011 = sub2ind (sval, idx(:, 1), idx(:, 2)+1, idx(:, 3)+1); + i110 = sub2ind (sval, idx(:, 1)+1, idx(:, 2)+1, idx(:, 3)); + i111 = sub2ind (sval, idx(:, 1)+1, idx(:, 2)+1, idx(:, 3)+1 ); + Bx = frac(:, 1); + By = frac(:, 2); + Bz = frac(:, 3); + Dx = ... + val( i000 ) .* -1 .* (1 .- By) .* (1 .- Bz) .+ ... + val( i100 ) .* (1 .- By) .* (1 .- Bz) .+ ... + val( i010 ) .* -1 .* By .* (1 .- Bz) .+ ... + val( i001 ) .* -1 .* (1 .- By) .* Bz .+ ... + val( i011 ) .* -1 .* By .* Bz .+ ... + val( i101 ) .* (1 .- By) .* Bz .+ ... + val( i110 ) .* By .* (1 .- Bz) .+ ... + val( i111 ) .* By .* Bz; + Dy = ... + val( i000 ) .* (1 .- Bx) .* -1 .* (1 .- Bz) .+ ... + val( i100 ) .* Bx .* -1 .* (1 .- Bz) .+ ... + val( i010 ) .* (1 .- Bx) .* (1 .- Bz) .+ ... + val( i001 ) .* (1 .- Bx) .* -1 .* Bz .+ ... + val( i011 ) .* (1 .- Bx) .* Bz .+ ... + val( i101 ) .* Bx .* -1 .* Bz .+ ... + val( i110 ) .* Bx .* (1 .- Bz) .+ ... + val( i111 ) .* Bx .* Bz; + Dz = ... + val( i000 ) .* (1 .- Bx) .* (1 .- By) .* -1 .+ ... + val( i100 ) .* Bx .* (1 .- By) .* -1 .+ ... + val( i010 ) .* (1 .- Bx) .* By .* -1 .+ ... + val( i001 ) .* (1 .- Bx) .* (1 .- By) .+ ... + val( i011 ) .* (1 .- Bx) .* By + ... + val( i101 ) .* Bx .* (1 .- By) .+ ... + val( i110 ) .* Bx .* By .* -1 .+ ... + val( i111 ) .* Bx .* By; +endfunction + +function [idx, frac] = cube_idx(x, y, z, v) + idx = zeros (size (v)); + frac = zeros (size (v)); + idx(:, 2) = lookup (x(2:end-1), v(:, 1)) + 1; + frac(:, 2) = (v(:, 1) - x(idx(:, 2)) )... + ./ (x(idx(:, 2)+1) - x(idx(:, 2))); + idx(:, 1) = lookup (y(2:end-1), v(:, 2)) + 1; + frac(:, 1) = (v(:, 2) - y(idx(:, 1))) ... + ./ (y(idx(:, 1)+1) - y(idx(:, 1))); + idx(:, 3) = lookup (z(2:end-1), v(:, 3)) + 1; + frac(:, 3) = (v(:, 3) - z(idx(:, 3))) ... + ./ (z(idx(:, 3)+1) - z(idx(:, 3))); +endfunction \ No newline at end of file diff --git a/scripts/plot/__marching_cube__.m b/scripts/plot/__marching_cube__.m new file mode 100644 --- /dev/null +++ b/scripts/plot/__marching_cube__.m @@ -0,0 +1,505 @@ +## Copyright (C) 2009 Martin Helm +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see http://www.gnu.org/licenses/gpl.html. +## +## Author: Martin Helm + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{t}, @var{p}, @var{col}] =} __marching_cube__ (@var{x}, @var{y}, @var{z}, @var{c}, @var{iso}, @var{color}) +## Undocumented internal function. +## @end deftypefn + +## usage: [T, P] = marching_cube( XX, YY, ZZ, C, ISO) +## usage: [T, P, COL] = marching_cube( XX, YY, ZZ, C, ISO, COLOR) +## +## Calculates the triangulation T with points P for the isosurface +## with level ISO. XX, YY, ZZ are meshgrid like values for the +## cube and C holds the scalar values of the field, +## COLOR holds additinal scalar values for coloring the surface. +## The orientation of the triangles is choosen such that the +## normals point from the lower values to the higher values. +## +## edgeTable and triTable are taken from Paul Bourke +## (http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/) +## Based on tables by Cory Gene Bloyd +## +## Example: +## +## x = linspace(0, 2, 20); +## y = linspace(0, 2, 20); +## z = linspace(0, 2, 20); +## +## [ xx, yy, zz ] = meshgrid(x, y, z); +## +## c = (xx-.5).^2 + (yy-.5).^2 + (zz-.5).^2; +## [T, p] = marching_cube(xx, yy, zz, c, 0.5); +## trimesh(T, p(:, 1), p(:, 2), p(:, 3)); +## +## with jhandles you can also use the patch function to visualize +## +## clf +## pa = patch('Faces',T,'Vertices',p,'FaceVertexCData',p, ... +## 'FaceColor','interp', 'EdgeColor', 'none'); +## set(pa, "VertexNormals", -get(pa, "VertexNormals")) # revert normals +## view(-30, 30) +## set(pa, "FaceLighting", "gouraud") +## light( "Position", [1 1 5]) +## + +function [T, p, col] = __marching_cube__( xx, yy, zz, c, iso, colors) + + persistent edge_table=[]; + persistent tri_table=[]; + + calc_cols = false; + lindex = 4; + + if (isempty (tri_table) || isempty (edge_table)) + [edge_table, tri_table] = init_mc (); + endif + + if ((nargin != 5 && nargin != 6) || (nargout != 2 && nargout != 3)) + print_usage (); + endif + + if (!ismatrix (xx) || !ismatrix (yy) || !ismatrix (zz) || !ismatrix (c) || ... + ndims (xx) != 3 || ndims (yy) != 3 || ndims (zz) != 3 || ndims (c) != 3) + error ("xx, yy, zz, c have to be matrizes of dim 3"); + endif + + if (!size_equal (xx, yy, zz, c)) + error ("xx, yy, zz, c are not the same size"); + endif + + if (any (size (xx) < [2 2 2])) + error ("grid size has to be at least 2x2x2"); + endif + + if (!isscalar (iso)) + error ("iso needs to be scalar value"); + endif + + if (nargin == 6) + if ( !ismatrix (colors) || ndims (colors) != 3 || size (colors) != size (c) ) + error ( "color has to be matrix of dim 3 and of same size as c" ); + endif + calc_cols = true; + lindex = 5; + endif + + n = size (c) - 1; + + ## phase I: assign information to each voxel which edges are intersected by + ## the isosurface + cc = zeros (n(1), n(2), n(3), "uint16"); + cedge = zeros (size (cc), "uint16"); + + vertex_idx = {1:n(1), 1:n(2), 1:n(3); ... + 2:n(1)+1, 1:n(2), 1:n(3); ... + 2:n(1)+1, 2:n(2)+1, 1:n(3); ... + 1:n(1), 2:n(2)+1, 1:n(3); ... + 1:n(1), 1:n(2), 2:n(3)+1; ... + 2:n(1)+1, 1:n(2), 2:n(3)+1; ... + 2:n(1)+1, 2:n(2)+1, 2:n(3)+1; ... + 1:n(1), 2:n(2)+1, 2:n(3)+1 }; + + ## calculate which vertices have values higher than iso + for ii=1:8 + idx = c(vertex_idx{ii, :}) > iso; + cc(idx) = bitset (cc(idx), ii); + endfor + + cedge = edge_table(cc+1); # assign the info about intersected edges + id = find (cedge); # select only voxels which are intersected + if (isempty (id)) + T = p = col = []; + return + endif + + ## phase II: calculate the list of intersection points + xyz_off = [1, 1, 1; 2, 1, 1; 2, 2, 1; 1, 2, 1; 1, 1, 2; 2, 1, 2; 2, 2, 2; 1, 2, 2]; + edges = [1 2; 2 3; 3 4; 4 1; 5 6; 6 7; 7 8; 8 5; 1 5; 2 6; 3 7; 4 8]; + offset = sub2ind (size (c), xyz_off(:, 1), xyz_off(:, 2), xyz_off(:, 3)) -1; + pp = zeros (length (id), lindex, 12); + ccedge = [vec(cedge(id)), id]; + ix_offset=0; + for jj=1:12 + id__ = bitget (ccedge(:, 1), jj); + id_ = ccedge(id__, 2); + [ix iy iz] = ind2sub (size (cc), id_); + id_c = sub2ind (size (c), ix, iy, iz); + id1 = id_c + offset(edges(jj, 1)); + id2 = id_c + offset(edges(jj, 2)); + if (calc_cols) + pp(id__, 1:5, jj) = [vertex_interp(iso, xx(id1), yy(id1), zz(id1), ... + xx(id2), yy(id2), zz(id2), c(id1), c(id2), colors(id1), colors(id2)), ... + (1:size (id_, 1))' + ix_offset ]; + else + pp(id__, 1:4, jj) = [vertex_interp(iso, xx(id1), yy(id1), zz(id1), ... + xx(id2), yy(id2), zz(id2), c(id1), c(id2)), ... + (1:size (id_, 1))' + ix_offset ]; + endif + ix_offset += size (id_, 1); + endfor + + ## phase III: calculate the triangulation from the point list + T = []; + tri = tri_table(cc(id)+1, :); + for jj=1:3:15 + id_ = find (tri(:, jj)>0); + p = [id_, lindex*ones(size (id_, 1), 1),tri(id_, jj:jj+2)]; + if (!isempty (p)) + p1 = sub2ind (size (pp), p(:,1), p(:,2), p(:,3)); + p2 = sub2ind (size (pp), p(:,1), p(:,2), p(:,4)); + p3 = sub2ind (size (pp), p(:,1), p(:,2), p(:,5)); + T = [T; pp(p1), pp(p2), pp(p3)]; + endif + endfor + + p = []; + col = []; + for jj = 1:12 + idp = pp(:, lindex, jj) > 0; + if (any (idp)) + p(pp(idp, lindex, jj), 1:3) = pp(idp, 1:3, jj); + if (calc_cols) + col(pp(idp, lindex, jj),1) = pp(idp, 4, jj); + endif + endif + endfor +endfunction + +function p = vertex_interp(isolevel,p1x, p1y, p1z,... + p2x, p2y, p2z,valp1,valp2, col1, col2) + + if (nargin == 9) + p = zeros (length (p1x), 3); + elseif (nargin == 11) + p = zeros (length (p1x), 4); + else + error ("Wrong number of arguments"); + endif + mu = zeros (length (p1x), 1); + id = abs (valp1-valp2) < (10*eps) .* (abs (valp1) .+ abs (valp2)); + if (any (id)) + p(id, 1:3) = [ p1x(id), p1y(id), p1z(id) ]; + if (nargin == 11) + p(id, 4) = col1(id); + endif + endif + nid = !id; + if (any (nid)) + mu(nid) = (isolevel - valp1(nid)) ./ (valp2(nid) - valp1(nid)); + p(nid, 1:3) = [p1x(nid) + mu(nid) .* (p2x(nid) - p1x(nid)), ... + p1y(nid) + mu(nid) .* (p2y(nid) - p1y(nid)), ... + p1z(nid) + mu(nid) .* (p2z(nid) - p1z(nid))]; + if (nargin == 11) + p(nid, 4) = col1(nid) + mu(nid) .* (col2(nid) - col1(nid)); + endif + endif +endfunction + +function [edge_table, tri_table] = init_mc() + edge_table = [ + 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, ... + 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, ... + 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, ... + 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, ... + 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, ... + 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, ... + 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, ... + 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, ... + 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, ... + 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, ... + 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, ... + 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, ... + 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, ... + 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, ... + 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , ... + 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, ... + 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, ... + 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, ... + 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, ... + 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, ... + 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, ... + 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, ... + 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, ... + 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, ... + 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, ... + 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, ... + 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, ... + 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, ... + 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, ... + 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, ... + 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, ... + 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 ]; + + tri_table =[ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1; + 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1; + 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1; + 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1; + 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1; + 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1; + 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1; + 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1; + 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1; + 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1; + 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1; + 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1; + 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1; + 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1; + 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1; + 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1; + 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1; + 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1; + 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1; + 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1; + 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1; + 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1; + 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1; + 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1; + 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1; + 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1; + 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1; + 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1; + 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1; + 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1; + 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1; + 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1; + 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1; + 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1; + 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1; + 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1; + 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1; + 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1; + 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1; + 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1; + 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1; + 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1; + 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1; + 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1; + 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1; + 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1; + 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1; + 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1; + 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1; + 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1; + 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1; + 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1; + 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1; + 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1; + 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1; + 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1; + 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1; + 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1; + 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1; + 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1; + 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1; + 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1; + 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1; + 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1; + 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1; + 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1; + 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1; + 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1; + 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1; + 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1; + 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1; + 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1; + 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1; + 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1; + 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1; + 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1; + 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1; + 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1; + 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1; + 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1; + 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1; + 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1; + 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1; + 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1; + 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1; + 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1; + 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1; + 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1; + 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1; + 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1; + 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1; + 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1; + 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1; + 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1; + 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1; + 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1; + 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1; + 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1; + 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1; + 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1; + 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1; + 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1; + 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1; + 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1; + 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1; + 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1; + 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1; + 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1; + 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1; + 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1; + 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1; + 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1; + 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1; + 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1; + 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1; + 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1; + 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1; + 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1; + 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1; + 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1; + 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1; + 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1; + 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1; + 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1; + 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1; + 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1; + 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1; + 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1; + 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1; + 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1; + 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1; + 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1; + 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1; + 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1; + 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1; + 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1; + 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1; + 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1; + 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1; + 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1; + 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1; + 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1; + 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1; + 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1; + 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1; + 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1; + 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1; + 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1; + 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1; + 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1; + 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1; + 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1; + 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1; + 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1; + 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1; + 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1; + 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1; + 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1; + 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1; + 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1; + 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1; + 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1; + 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1; + 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1; + 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1; + 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1; + 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1; + 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1; + 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1; + 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1; + 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1; + 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1; + 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1; + 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1; + 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1; + 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1; + 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1; + 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1; + 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1; + 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1; + 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1; + 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1; + 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1; + 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1; + 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1; + 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1; + 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1; + 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1; + 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1; + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ] + 1; +endfunction \ No newline at end of file diff --git a/scripts/plot/__patch__.m b/scripts/plot/__patch__.m --- a/scripts/plot/__patch__.m +++ b/scripts/plot/__patch__.m @@ -27,165 +27,280 @@ ## Author: Kai Habel -function [h, fail] = __patch__ (p, varargin) - - fail = false; +function [h, failed] = __patch__ (p, varargin) - if (nargin < 3) - fail = true; - return; - endif - - iarg = 1; - have_x = have_z = have_c = have_faces = false; - if (isnumeric (varargin{1})) - if (! isnumeric (varargin{2})) - fail = true; - return; - endif + failed = false; - x = varargin{1}; - y = varargin{2}; - have_x = true; - iarg += 2; - - if (nargin > 3 && ndims (varargin{3}) == 2 && ndims (x) == 2 - && size_equal(x, varargin{3}) && !ischar(varargin{3})) - z = varargin{3}; - have_z = true; - iarg++; - endif - elseif (ischar (varargin{1}) - && (strcmpi (varargin{1}, "faces") - || strcmpi (varargin{1}, "vertices"))) - if (! isnumeric (varargin{2})) - fail = true; - return; + if (isstruct (varargin{1})) + if (isfield (varargin{1}, "vertices") && isfield (varargin{1}, "faces")) + args{1} = "faces"; + args{2} = field(varargin{1}, "faces"); + args{3} = "vertices"; + args{4} = field(varargin{1}, "vertices"); + args{5} = "facevertexcdata"; + if (isfield (varargin{1}, "facevertexcdata")) + args{6} = field(varargin{1}, "facevertexcdata"); + else + args{6} = []; + endif + args = [args; varargin(2:end)]; + args = setdata (args); + else + failed = true; endif - - if (strcmpi (varargin{1}, "faces")) - faces = varargin{2}; - if (strcmpi (varargin{3}, "vertices")) - vert = varargin{4}; - have_faces = true; - endif - elseif (strcmpi (varargin{1}, "vertices")) - vert = varargin{2}; - if (strcmpi (varargin{3}, "faces")) - faces = varargin{4}; - have_faces = true; - endif - endif - if (!have_faces) - fail = true; - return; + elseif (isnumeric (varargin{1})) + if (nargin < 3 || ! isnumeric (varargin{2})) + failed = true; else - iarg += 4; - endif - endif + x = varargin{1}; + y = varargin{2}; + iarg = 3; + + if (nargin > 3 && ndims (varargin{3}) == 2 && ndims (x) == 2 + && size_equal(x, varargin{3}) && !ischar(varargin{3})) + z = varargin{3}; + iarg++; + else + z = []; + endif - if ((have_x || have_faces) && nargin > iarg) - if (isnumeric (varargin{iarg})) - c = varargin{iarg}; - have_c = true; - iarg++; + if (isvector (x)) + x = x(:); + y = y(:); + z = z(:); + endif + args{1} = "xdata"; + args{2} = x; + args{3} = "ydata"; + args{4} = y; + args{5} = "zdata"; + args{6} = z; + + if (isnumeric (varargin{iarg})) + c = varargin{iarg}; + iarg++; + + if (ndims (c) == 3 && size (c, 2) == 1) + c = permute (c, [1, 3, 2]); + endif - if (ndims (c) == 3 && size (c, 2) == 1) - c = permute (c, [1, 3, 2]); + if (isvector (c) && numel (c) == columns (x)) + if (isnan (c)) + args{7} = "facecolor"; + args{8} = [1, 1, 1]; + args{9} = "cdata"; + args{10} = c; + elseif (isnumeric (c)) + args{7} = "facecolor"; + args{8} = "flat"; + args{9} = "cdata"; + args{10} = c; + else + error ("patch: color value not valid"); + endif + elseif (size (c, ndims (c)) == 3) + args{7} = "facecolor"; + args{8} = "flat"; + args{9} = "cdata"; + args{10} = c; + else + ## Color Vectors + if (rows (c) != rows (x) || rows (c) != length (y)) + error ("patch: size of x, y, and c must be equal") + else + args{7} = "facecolor"; + args{8} = "interp"; + args{9} = "cdata"; + args{10} = []; + endif + endif + elseif (ischar (varargin{iarg}) && rem (nargin - iarg, 2) != 0) + ## Assume that any additional argument over an even number is + ## color string. + args{7} = "facecolor"; + args{8} = tolower (varargin{iarg}); + args{9} = "cdata"; + args{10} = []; + iarg++; + else + args{7} = "facecolor"; + args{8} = [0, 1, 0]; + args{9} = "cdata"; + args{10} = []; endif - elseif (ischar (varargin{iarg}) && rem (nargin - iarg, 2) != 0) - ## Assume that any additional argument over an even number is - ## color string. - c = tolower (varargin{iarg}); - have_c = true; - iarg++; + + args = [args, varargin(iarg:end)]; + args = setvertexdata (args); + endif + else + args = varargin; + if (any(cellfun (@(x) strcmpi(x,"faces") || strcmpi(x, "vertices"), args))) + args = setdata (args); + else + args = setvertexdata (args); endif endif - if (rem (nargin - iarg, 2) != 0) - fail = true; - return; + if (!failed) + h = __go_patch__ (p, args {:}); + + ## Setup listener functions + addlistener (h, "xdata", @update_data); + addlistener (h, "ydata", @update_data); + addlistener (h, "zdata", @update_data); + addlistener (h, "cdata", @update_data); + + addlistener (h, "faces", @update_fvc); + addlistener (h, "vertices", @update_fvc); + addlistener (h, "facevertexcdata", @update_fvc); + endif +endfunction + +function args = delfields(args, flds) + idx = cellfun (@(x) any (strcmpi (x, flds)), args); + idx = idx | [false, idx(1:end-1)]; + args (idx) = []; +endfunction + +function args = setdata (args) + args = delfields (args, {"xdata", "ydata", "zdata", "cdata"}); + nargs = length (args); + idx = find (cellfun (@(x) strcmpi (x, "faces"), args)) + 1; + if (idx > nargs) + faces = []; + else + faces = args {idx}; + endif + idx = find (cellfun (@(x) strcmpi (x, "vertices"), args)) + 1; + if (idx > nargs) + vert = []; + else + vert = args {idx}; + endif + idx = find (cellfun (@(x) strcmpi (x, "facecolor"), args)) + 1; + if (isempty(idx) || idx > nargs) + fc = "flat"; + else + fc = args {idx}; + endif + idx = find (cellfun (@(x) strcmpi (x, "facevertexcdata"), args)) + 1; + if (isempty(idx) || idx > nargs) + fvc = []; + else + fvc = args {idx}; endif - if (have_x) - if (isvector (x)) - x = x(:); - y = y(:); - if (have_z) - z = z(:); - endif - endif - [nr, nc] = size (x); - if (have_z) - vert = [x(:), y(:), z(:)]; - else - vert = [x(:), y(:)]; - endif - faces = reshape (1:numel(x), rows (x), columns (x)); - faces = faces'; - elseif (have_faces) - nr = size (faces, 2); - nc = size (faces, 1); - idx = faces .'; - t1 = isnan (idx); - if (any (t1(:))) - t2 = find (t1 != t1([2:end,end],:)); - idx (t1) = idx (t2 (cell2mat (cellfun (@(x) x(1)*ones(1,x(2)), + nr = size (faces, 2); + nc = size (faces, 1); + idx = faces .'; + t1 = isnan (idx); + if (any (t1(:))) + t2 = find (t1 != t1([2:end,end],:)); + idx (t1) = idx (t2 (cell2mat (cellfun (@(x) x(1)*ones(1,x(2)), mat2cell ([1 : nc; sum(t1)], 2, ones(1,nc)), - "UniformOutput", false)))); - endif - x = reshape (vert(:,1)(idx), size (idx)); - y = reshape (vert(:,2)(idx), size (idx)); - if (size(vert,2) > 2) - have_z = true; - z = reshape (vert(:,3)(idx), size (idx)); - endif + "UniformOutput", false)))); + endif + x = reshape (vert(:,1)(idx), size (idx)); + y = reshape (vert(:,2)(idx), size (idx)); + if (size(vert,2) > 2) + z = reshape (vert(:,3)(idx), size (idx)); else - error ("patch: not supported"); + z = []; endif - cargs = {}; - if (have_c) - if (ischar (c)) - cargs{1} = "facecolor"; - cargs{2} = c; - elseif (isvector (c) && numel (c) == nc) - if (isnan (c)) - cargs{1} = "facecolor"; - cargs{2} = [1, 1, 1]; - cargs{3} = "cdata"; - cargs{4} = c; - elseif (isnumeric (c)) - cargs{1} = "facecolor"; - cargs{2} = "flat"; - cargs{3} = "cdata"; - cargs{4} = c; + if (ischar (fc) && (strcmpi (fc, "flat") || strcmpi (fc, "interp"))) + if (size(fvc, 1) == nc || size (fvc, 1) == 1) + c = reshape (fvc, [1, size(fvc)]); + else + if (size(fvc, 2) == 3) + c = cat(3, reshape (fvc(idx, 1), size(idx)), + reshape (fvc(idx, 2), size(idx)), + reshape (fvc(idx, 3), size(idx))); else - error ("patch: color value not valid"); - endif - elseif (size (c, ndims (c)) == 3) - cargs{1} = "facecolor"; - cargs{2} = "flat"; - cargs{3} = "cdata"; - cargs{4} = c; - else - ## Color Vectors - if (rows (c2) != rows (x) || rows (c2) != length (y)) - error ("patch: size of x, y, and c must be equal") - else - cargs{1} = "facecolor"; - cargs{2} = "interp"; + c = reshape (fvc(idx), size(idx)); endif endif else - cargs{1} = "facecolor"; - cargs{2} = [0, 1, 0]; + c = []; + endif + args = {"xdata", x, "ydata", y, "zdata", z, "cdata", c, args{:}}; +endfunction + +function args = setvertexdata (args) + args = delfields (args, {"vertices", "faces", "facevertexcdata"}); + nargs = length (args); + idx = find (cellfun (@(x) strcmpi (x, "xdata"), args)) + 1; + if (idx > nargs) + x = []; + else + x = args {idx}; + endif + idx = find (cellfun (@(x) strcmpi (x, "ydata"), args)) + 1; + if (idx > nargs) + y = []; + else + y = args {idx}; + endif + idx = find (cellfun (@(x) strcmpi (x, "zdata"), args)) + 1; + if (isempty(idx) || idx > nargs) + z = []; + else + z = args {idx}; + endif + idx = find (cellfun (@(x) strcmpi (x, "facecolor"), args)) + 1; + if (isempty(idx) || idx > nargs) + fc = "flat"; + else + fc = args {idx}; + endif + idx = find (cellfun (@(x) strcmpi (x, "cdata"), args)) + 1; + if (isempty(idx) || idx > nargs) + c = []; + else + c = args {idx}; endif - h = __go_patch__ (p, "xdata", x, "ydata", y, "faces", faces, - "vertices", vert, cargs{:}, varargin{iarg:end}); - if (have_z) - set (h, "zdata", z); + [nr, nc] = size (x); + if (!isempty (z)) + vert = [x(:), y(:), z(:)]; + else + vert = [x(:), y(:)]; + endif + faces = reshape (1:numel(x), rows (x), columns (x)); + faces = faces'; + + if (ischar (fc) && (strcmpi (fc, "flat") || strcmpi (fc, "interp"))) + if (ndims (c) == 3) + fvc = reshape (c, size (c, 1) * size (c, 2), size(c, 3)); + else + fvc = c(:); + endif + else + fvc = []; endif - + + args = {"faces", faces, "vertices", vert, "facevertexcdata", fvc, args{:}}; +endfunction + +function update_data (h, d) + update_handle (h, false); +endfunction + +function update_fvc (h, d) + update_handle (h, true); endfunction + +function update_handle (h, isfv) + persistent recursive = false; + + if (! recursive) + recursive = true; + f = get (h); + if (isfvc) + set (h, setvertexdata ([fieldnames(f), struct2cell(f)].'(:)){:}); + else + set (h, setdata ([fieldnames(f), struct2cell(f)].'(:)){:}); + endif + recursive = false; + endif +endfunction diff --git a/scripts/plot/isocolors.m b/scripts/plot/isocolors.m new file mode 100644 --- /dev/null +++ b/scripts/plot/isocolors.m @@ -0,0 +1,168 @@ +## Copyright (C) 2009 Martin Helm +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see http://www.gnu.org/licenses/gpl.html. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{cd}] =} isocolors (@var{c}, @var{v}) +## @deftypefnx {Function File} {[@var{cd}] =} isocolors (@var{x}, @var{y}, @var{z}, @var{c}, @var{v}) +## @deftypefnx {Function File} {[@var{cd}] =} isocolors (@var{x}, @var{y}, @var{z}, @var{r}, @var{g}, @var{b}, @var{v}) +## @deftypefnx {Function File} {[@var{cd}] =} isocolors (@var{r}, @var{g}, @var{b}, @var{v}) +## @deftypefnx {Function File} {[@var{cd}] =} isocolors (@dots{}, @var{p}) +## @deftypefnx {Function File} isocolors (@dots{}) +## +## If called with one output argument and the first input argument +## @var{c} is a three--dimensional array that contains color values and +## the second input argument @var{v} keeps the vertices of a geometry +## then return a matrix @var{cd} with color data information for the +## geometry at computed points +## @command{[x, y, z] = meshgrid (1:l, 1:m, 1:n)}. The output argument +## @var{cd} can be taken to manually set FaceVertexCData of a patch. +## +## If called with further input arguments @var{x}, @var{y} and @var{z} +## which are three--dimensional arrays of the same size than @var{c} +## then the color data is taken at those given points. Instead of the +## color data @var{c} this function can also be called with RGB values +## @var{r}, @var{g}, @var{b}. If input argumnets @var{x}, @var{y}, +## @var{z} are not given then again @command{meshgrid} computed values +## are taken. +## +## Optionally, the patch handle @var{p} can be given as the last input +## argument to all variations of function calls instead of the vertices +## data @var{v}. Finally, if no output argument is given then directly +## change the colors of a patch that is given by the patch handle +## @var{p}. +## +## For example, +## @example +## function [] = isofinish (p) +## set (gca, "DataAspectRatioMode", "manual", \ +## "DataAspectRatio", [1 1 1]); +## set (p, "FaceColor", "interp"); +## ## set (p, "FaceLighting", "flat"); +## ## light ("Position", [1 1 5]); ## Available with JHandles +## endfunction +## +## N = 15; ## Increase number of vertices in each direction +## iso = .4; ## Change isovalue to .1 to display a sphere +## lin = linspace (0, 2, N); +## [x, y, z] = meshgrid (lin, lin, lin); +## c = abs ((x-.5).^2 + (y-.5).^2 + (z-.5).^2); +## figure (); ## Open another figure window +## +## subplot (2, 2, 1); view (-38, 20); +## [f, v] = isosurface (x, y, z, c, iso); +## p = patch ("Faces", f, "Vertices", v, "EdgeColor", "none"); +## cdat = rand (size (c)); ## Compute random patch color data +## isocolors (x, y, z, cdat, p); ## Directly set colors of patch +## isofinish (p); ## Call user function isofinish +## +## subplot (2, 2, 2); view (-38, 20); +## p = patch ("Faces", f, "Vertices", v, "EdgeColor", "none"); +## [r, g, b] = meshgrid (lin, 2-lin, 2-lin); +## cdat = isocolors (x, y, z, c, v); ## Compute color data vertices +## set (p, "FaceVertexCData", cdat); ## Set color data manually +## isofinish (p); +## +## subplot (2, 2, 3); view (-38, 20); +## p = patch ("Faces", f, "Vertices", v, "EdgeColor", "none"); +## cdat = isocolors (r, g, b, c, p); ## Compute color data patch +## set (p, "FaceVertexCData", cdat); ## Set color data manually +## isofinish (p); +## +## subplot (2, 2, 4); view (-38, 20); +## p = patch ("Faces", f, "Vertices", v, "EdgeColor", "none"); +## r = g = b = repmat ([1:N] / N, [N, 1, N]); ## Black to white +## cdat = isocolors (x, y, z, r, g, b, v); +## set (p, "FaceVertexCData", cdat); +## isofinish (p); +## @end example +## +## @seealso{isosurface, isonormals, isocaps} +## +## @end deftypefn + +## Author: Martin Helm + +function varargout = isocolors(varargin) + calc_rgb = false; + switch nargin + case 2 + c = varargin{1}; + vp = varargin{2}; + x = 1:size (c, 2); + y = 1:size (c, 1); + z = 1:size (c, 3); + case 4 + calc_rgb = true; + R = varargin{1}; + G = varargin{2}; + B = varargin{3}; + vp = varargin{4}; + x = 1:size (R, 1); + y = 1:size (R, 2); + z = 1:size (R, 3); + case 5 + x = varargin{1}; + y = varargin{2}; + z = varargin{3}; + c = varargin{4}; + vp = varargin{5}; + case 7 + calc_rgb = true; + x = varargin{1}; + y = varargin{2}; + z = varargin{3}; + R = varargin{4}; + G = varargin{5}; + B = varargin{6}; + vp = varargin{7}; + otherwise + print_usage (); + endswitch + if (ismatrix (vp) && size (vp,2) == 3) + pa = []; + v = vp; + elseif ( ishandle (vp) ) + pa = vp; + v = get (pa, "Vertices"); + else + error("Last argument is no vertex list and no patch handle"); + endif + if ( calc_rgb ) + new_col = zeros (size (v, 1), 3); + new_col(:, 1) = __interp_cube__ (x, y, z, R, v, "values" ); + new_col(:, 2) = __interp_cube__ (x, y, z, G, v, "values" ); + new_col(:, 3) = __interp_cube__ (x, y, z, B, v, "values" ); + else + new_col = __interp_cube__ (x, y, z, c, v, "values" ); + endif + switch nargout + case 0 + if (!isempty (pa)) + set (pa, "FaceVertexCData", new_col); + endif + case 1 + varargout = {new_col}; + otherwise + print_usage (); + endswitch +endfunction + +%!test +%! [x, y, z] = meshgrid (0:.5:2, 0:.5:2, 0:.5:2); +%! c = (x-.5).^2 + (y-.5).^2 + (z-.5).^2; +%! [f, v] = isosurface (x, y, z, c, .4); +%! cdat = isocolors (x, y, z, c, v); +%! assert (size (cdat, 1) == size (v, 1)); +## Can't create a patch handle for tests without a figure diff --git a/scripts/plot/isonormals.m b/scripts/plot/isonormals.m new file mode 100644 --- /dev/null +++ b/scripts/plot/isonormals.m @@ -0,0 +1,78 @@ +## Copyright (C) 2009 Martin Helm +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see http://www.gnu.org/licenses/gpl.html. +## +## Author: Martin Helm + +## usage: NORMALS = isonormals(X,Y,Z,V,VERT) +## usage: NORMALS = isonormals(V,VERT) +## usage: NORMALS = isonormals(V,P) +## usage: NORMALS = isonormals(X,Y,Z,V,P) +## usage: NORMALS = isonormals(...,'negate') +## usage: isonormals(V,P) +## usage: isonormals(X,Y,Z,V,P) +## + +function varargout = isonormals(varargin) + na = nargin; + negate = false; + if (ischar (varargin{nargin})) + na = nargin-1; + if (strcmp (lower (varargin{nargin}), "negate")) + negate = true; + else + error ("Unknown option '%s'", varargin{nargin}); + endif + endif + switch na + case 2 + c = varargin{1}; + vp = varargin{2}; + x = 1:size (c, 2); + y = 1:size (c, 1); + z = 1:size (c, 3); + case 5 + x = varargin{1}; + y = varargin{2}; + z = varargin{3}; + c = varargin{4}; + vp = varargin{5}; + otherwise + print_usage (); + endswitch + if (ismatrix (vp) && size (vp,2) == 3) + pa = []; + v = vp; + elseif (ishandle (vp)) + pa = vp; + v = get (pa, "Vertices"); + else + error ("Last argument is no vertex list and no patch handle"); + endif + if (negate) + normals = -__interp_cube__ (x, y, z, c, v, "normals"); + else + normals = __interp_cube__ (x, y, z, c, v, "normals"); + endif + switch nargout + case 0 + if (!isempty (pa)) + set (pa, "VertexNormals", normals); + endif + case 1 + varargout = {normals}; + otherwise + print_usage (); + endswitch +endfunction \ No newline at end of file diff --git a/scripts/plot/isosurface.m b/scripts/plot/isosurface.m new file mode 100644 --- /dev/null +++ b/scripts/plot/isosurface.m @@ -0,0 +1,215 @@ +## Copyright (C) 2009 Martin Helm +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see http://www.gnu.org/licenses/gpl.html. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{fv}] =} isosurface (@var{val}, @var{iso}) +## @deftypefnx {Function File} {[@var{fv}] =} isosurface (@var{x}, @var{y}, @var{z}, @var{val}, @var{iso}) +## @deftypefnx {Function File} {[@var{fv}] =} isosurface (@dots{}, "noshare", "verbose") +## @deftypefnx {Function File} {[@var{fvc}] =} isosurface (@dots{}, @var{col}) +## @deftypefnx {Function File} {[@var{f}, @var{v}] =} isosurface (@var{x}, @var{y}, @var{z}, @var{val}, @var{iso}) +## @deftypefnx {Function File} {[@var{f}, @var{v}, @var{c}] =} isosurface (@var{x}, @var{y}, @var{z}, @var{val}, @var{iso}, @var{col}) +## @deftypefnx {Function File} {} isosurface (@var{x}, @var{y}, @var{z}, @var{val}, @var{iso}, @var{col}, @var{opt}) +## +## If called with one output argument and the first input argument +## @var{val} is a three--dimensional array that contains the data of an +## isosurface geometry and the second input argument @var{iso} keeps the +## isovalue as a scalar value then return a structure array @var{fv} +## that contains the fields @var{Faces} and @var{Vertices} at computed +## points @command{[x, y, z] = meshgrid (1:l, 1:m, 1:n)}. The output +## argument @var{fv} can directly be taken as an input argument for the +## @command{patch} function. +## +## If called with further input arguments @var{x}, @var{y} and @var{z} +## which are three--dimensional arrays with the same size than @var{val} +## then the volume data is taken at those given points. +## +## The string input argument "noshare" is only for compatibility and +## has no effect. If given the string input argument +## "verbose" then print messages to the command line interface about the +## current progress. +## +## If called with the input argument @var{col} which is a +## three-dimensional array of the same size than @var{val} then take +## those values for the interpolation of coloring the isosurface +## geometry. Add the field @var{FaceVertexCData} to the structure +## array @var{fv}. +## +## If called with two or three output arguments then return the +## information about the faces @var{f}, vertices @var{v} and color data +## @var{c} as seperate arrays instead of a single structure array. +## +## If called with no output argument then directly process the +## isosurface geometry with the @command{patch} command. +## +## For example +## +## @example +## [x, y, z] = meshgrid (1:5, 1:5, 1:5); +## val = rand (5, 5, 5); +## isosurface (x, y, z, val, .5); +## @end example +## +## will directly draw a random isosurface geometry in a graphics window. +## Another example for an isosurface geometry with different additional +## coloring +## +## @example +## N = 15; ## Increase number of vertices in each direction +## iso = .4; ## Change isovalue to .1 to display a sphere +## lin = linspace (0, 2, N); +## [x, y, z] = meshgrid (lin, lin, lin); +## c = abs ((x-.5).^2 + (y-.5).^2 + (z-.5).^2); +## figure (); ## Open another figure window +## +## subplot (2, 2, 1); view (-38, 20); +## [f, v] = isosurface (x, y, z, c, iso); +## p = patch ("Faces", f, "Vertices", v, "EdgeColor", "none"); +## set (gca, "DataAspectRatioMode","manual", "DataAspectRatio", [1 1 1]); +## # set (p, "FaceColor", "green", "FaceLighting", "phong"); +## # light ("Position", [1 1 5]); ## Available with the JHandles package +## +## subplot (2, 2, 2); view (-38, 20); +## p = patch ("Faces", f, "Vertices", v, "EdgeColor", "blue"); +## set (gca, "DataAspectRatioMode","manual", "DataAspectRatio", [1 1 1]); +## # set (p, "FaceColor", "none", "FaceLighting", "phong"); +## # light ("Position", [1 1 5]); +## +## subplot (2, 2, 3); view (-38, 20); +## [f, v, c] = isosurface (x, y, z, c, iso, y); +## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", c, \ +## "FaceColor", "interp", "EdgeColor", "none"); +## set (gca, "DataAspectRatioMode","manual", "DataAspectRatio", [1 1 1]); +## # set (p, "FaceLighting", "phong"); +## # light ("Position", [1 1 5]); +## +## subplot (2, 2, 4); view (-38, 20); +## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", c, \ +## "FaceColor", "interp", "EdgeColor", "blue"); +## set (gca, "DataAspectRatioMode","manual", "DataAspectRatio", [1 1 1]); +## # set (p, "FaceLighting", "phong"); +## # light ("Position", [1 1 5]); +## @end example +## +## @seealso{isocolors, isonormals, isocaps} +## +## @end deftypefn + +## Author: Martin Helm + +function varargout = isosurface(varargin) + + if (nargin < 2 || nargin > 8 || nargout > 3) + print_usage (); + endif + + calc_colors = false; + f = v = c = []; + verbose = false; + noshare = false; + if (nargin >= 5) + x = varargin{1}; + y = varargin{2}; + z = varargin{3}; + val = varargin{4}; + iso = varargin{5}; + if (nargin >= 6 && ismatrix (varargin{6})) + colors = varargin{6}; + calc_colors = true; + endif + else + val = varargin{1}; + [n1, n2, n3] = size (val); + [x, y, z] = meshgrid (1:n1, 1:n2, 1:n3); + iso = varargin{2}; + if (nargin >= 3 && ismatrix (varargin{3})) + colors = varargin{3}; + calc_colors = true; + endif + endif + if (calc_colors) + if (nargout == 2) + warning ( "Colors will be calculated, but you did not specify an output argument for it!" ); + endif + [fvc.faces, fvc.vertices, fvc.facevertexcdata] = __marching_cube__ (x, y, z, val, iso, colors); + else + [fvc.faces, fvc.vertices] = __marching_cube__ (x, y, z, val, iso); + endif + + if (isempty (fvc.vertices) || isempty (fvc.faces)) + warning ( "The resulting triangulation is empty" ); + endif + + switch (nargout) + case 0 + ## plot the calculated surface + newplot (); + if (calc_colors) + pa = patch ("Faces", fvc.faces, "Vertices", fvc.vertices, + "FaceVertexCData", fvc.facevertexcdata, + "FaceColor", "flat", "EdgeColor", "none"); + else + pa = patch ("Faces", fvc.faces, "Vertices", fvc.vertices, + "FaceColor", "g", "EdgeColor", "k"); + endif + if (! ishold ()) + set (gca(), "view", [-37.5, 30], + "xgrid", "on", "ygrid", "on", "zgrid", "on"); + endif + case 1 + varargout = {fvc}; + case 2 + varargout = {fvc.faces, fvc.vertices}; + case 3 + varargout = {fvc.faces, fvc.vertices, fvc.facevertexcdata}; + otherwise + print_usage (); + endswitch + +endfunction + + +%!shared x, y, z, val +%! [x, y, z] = meshgrid (0:1, 0:1, 0:1); ## Points for single +%! val = [0, 0; 0, 0]; ## cube and a 3--dim +%! val(:,:,2) = [0, 0; 1, 0]; ## array of values +%!test +%! fv = isosurface (x, y, z, val, 0.3); +%! assert (isfield (fv, "vertices"), true); +%! assert (isfield (fv, "faces"), true); +%! assert (size (fv.vertices), [3 3]); +%! assert (size (fv.faces), [1 3]); +%!test +%! fvc = isosurface (x, y, z, val, .3, y); +%! assert (isfield (fvc, "vertices"), true); +%! assert (isfield (fvc, "faces"), true); +%! assert (isfield (fvc, "facevertexcdata"), true); +%! assert (size (fvc.vertices), [3 3]); +%! assert (size (fvc.faces), [1 3]); +%! assert (size (fvc.facevertexcdata), [3 1]); +%!test +%! [f, v] = isosurface (x, y, z, val, .3); +%! assert (size (f), [1 3]); +%! assert (size (v), [3 3]); +%!test +%! [f, v, c] = isosurface (x, y, z, val, .3, y); +%! assert (size (f), [1 3]); +%! assert (size (v), [3 3]); +%! assert (size (c), [3 1]); + +%!demo +%! clf +%! [x,y,z] = meshgrid(-2:0.5:2, -2:0.5:2, -2:0.5:2); +%! v = x.^2 + y.^2 + z.^2; +%! isosurface (x, y, z, v, 1) \ No newline at end of file diff --git a/scripts/plot/patch.m b/scripts/plot/patch.m --- a/scripts/plot/patch.m +++ b/scripts/plot/patch.m @@ -19,7 +19,8 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} patch () ## @deftypefnx {Function File} {} patch (@var{x}, @var{y}, @var{c}) -## @deftypefnx {Function File} {} patch (@var{x}, @var{y}, @var{c}, @var{opts}) +## @deftypefnx {Function File} {} patch (@var{x}, @var{y}, @var{z}, @var{c}) +## @deftypefnx {Function File} {} patch (@var{fv}) ## @deftypefnx {Function File} {} patch ('Faces', @var{f}, 'Vertices', @var{v}, @dots{}) ## @deftypefnx {Function File} {} patch (@dots{}, @var{prop}, @var{val}) ## @deftypefnx {Function File} {} patch (@var{h}, @dots{}) @@ -29,7 +30,11 @@ ## ## For a uniform colored patch, @var{c} can be given as an RGB vector, ## scalar value referring to the current colormap, or string value (for -## example, "r" or "red"). +## example, "r" or "red"). +## +## If passed a structure @var{fv} contain the fields "vertices", "faces" +## and optionally "facevertexcdata", create the patch based on these +## properties. ## @end deftypefn ## Author: jwe @@ -42,15 +47,14 @@ unwind_protect axes (h); - [tmp, fail] = __patch__ (h, varargin{:}); + [tmp, failed] = __patch__ (h, varargin{:}); + if (failed) + print_usage (); + endif unwind_protect_cleanup axes (oldh); end_unwind_protect - if (fail) - print_usage (); - endif - if (nargout > 0) retval = tmp; endif @@ -93,6 +97,19 @@ %! patch('Faces',fac,'Vertices',vert,'FaceColor','r'); %!demo +%! ## Specify vertices and faces separately +%! clf +%! t1 = (1/16:1/8:1)'*2*pi; +%! t2 = ((1/16:1/16:1)' + 1/32)*2*pi; +%! x1 = sin(t1) - 0.8; +%! y1 = cos(t1); +%! x2 = sin(t2) + 0.8; +%! y2 = cos(t2); +%! vert = [x1, y1; x2, y2]; +%! fac = [1:8,NaN(1,8);9:24]; +%! patch('Faces',fac,'Vertices',vert,'FaceVertexCData', [0, 1, 0; 0, 0, 1]); + +%!demo %! ## Property change on multiple patches %! clf %! t1 = (1/16:1/8:1)'*2*pi; @@ -104,3 +121,18 @@ %! h = patch([x1,x2],[y1,y2],cat (3,[0,0],[1,0],[0,1])); %! pause (1); %! set (h, 'FaceColor', 'r'); + +%!demo +%! clf +%! vertices = [0, 0, 0; +%! 1, 0, 0; +%! 1, 1, 0; +%! 0, 1, 0; +%! 0.5, 0.5, 1]; +%! faces = [1, 2, 5; +%! 2, 3, 5; +%! 3, 4, 5; +%! 4, 1, 5]; +%! patch('Vertices', vertices, 'Faces', faces, ... +%! 'FaceVertexCData', jet(4), 'FaceColor', 'flat') +%! view (-37.5, 30)