# HG changeset patch # User Martin Helm # Date 1334410972 -7200 # Node ID f91b72aefe48918ca85bd7129836a8741b78f57f # Parent 26b2983a8acd6512c10a9ef92a139e36f059351e New Function, shrinkfaces.m * shrinkfaces.m: New File. * scripts/plot/module.mk: Add new file. diff -r 26b2983a8acd -r f91b72aefe48 scripts/plot/module.mk --- a/scripts/plot/module.mk Fri Apr 13 14:07:45 2012 -0400 +++ b/scripts/plot/module.mk Sat Apr 14 15:42:52 2012 +0200 @@ -162,6 +162,7 @@ plot/semilogyerr.m \ plot/shading.m \ plot/shg.m \ + plot/shrinkfaces.m \ plot/slice.m \ plot/sombrero.m \ plot/specular.m \ diff -r 26b2983a8acd -r f91b72aefe48 scripts/plot/shrinkfaces.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/plot/shrinkfaces.m Sat Apr 14 15:42:52 2012 +0200 @@ -0,0 +1,228 @@ +## Copyright (C) 2012 Martin Helm +## +## 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} shrinkfaces (@var{p}) +## @deftypefnx {Function File} shrinkfaces (@var{p}, @var{sf}) +## @deftypefnx {Function File} address@hidden =} shrinkfaces (@var{p}, @var{sf}) +## @deftypefnx {Function File} address@hidden =} shrinkfaces (@var{fv}, @var{sf}) +## @deftypefnx {Function File} address@hidden =} shrinkfaces (@var{f}, @var{v}, @var{sf}) +## @deftypefnx {Function File} address@hidden, @var{nv}] =} = shrinkfaces (@dots{}) +## +## @command{shrinkfaces} reduces the faces area for a given patch, structure or +## explicit faces and points matrices by a scale factor @var{sf}. The structure +## @var{fv} needs to contain the fields 'faces' and 'vertices'. +## If the factor @var{sf} is omited then a default of 0.3 is used. +## +## Calling the function without output parameters and a patch handle as first +## input argument performs the shrinking of the patch faces in place and redraws +## the patch. +## +## Called with one output argument it returns a structure with fields +## 'faces', 'vertices' and 'facevertexcdata' containing the data after shrinking +## which can then directly be used as input argument for the @command{patch} +## function. +## +## Performing the shrinking on faces which are not convex can lead to undesired +## results. +## +## +## For example +## +## @example +## @group +## [phi r] = meshgrid (linspace (0, 1.5*pi, 16), linspace (1, 2, 4)); +## tri = delaunay (phi(:), r(:)); +## v = [r(:).*sin(phi(:)) r(:).*cos(phi(:))]; +## clf () +## p = patch ("Faces", tri, "Vertices", v, "FaceColor", "none"); +## fv = shrinkfaces (p); +## patch (fv) +## axis equal +## grid on +## @end group +## @end example +## +## @noindent +## will draw a triangulated 3/4 circle and the corresponding shrinked version. +## +## The command +## +## @example +## @group +## demo shrinkfaces +## @end group +## @end example +## +## @noindent +## shows further examples how to use it. +## +## @seealso{patch} +## @end deftypefn + +## Author: Martin Helm + +function [nf,nv] = shrinkfaces (varargin) + + # begin: check input + if (nargin < 1 || nargin > 3 || nargout > 2) + print_usage () + endif + + sf = 0.3; + p = varargin{1}; + colors = []; + + if (ishandle (p) && nargin < 3) + faces = get (p, "Faces"); + vertices = get (p, "Vertices"); + colors = get (p, "FaceVertexCData"); + if (nargin == 2) + sf = varargin{2}; + endif + elseif (isstruct (p) && nargin < 3) + faces = p.faces; + vertices = p.vertices; + if (isfield (p, "facevertexcdata")) + colors = p.facevertexcdata; + endif + if (nargin == 2) + sf = varargin{2}; + endif + elseif (ismatrix (p) && nargin >= 2 && ismatrix (varargin{2})) + faces = p; + vertices = varargin{2}; + if (nargin == 3) + sf = varargin{3}; + endif + else + print_usage () + endif + + if (! isscalar (sf) || sf <= 0) + error ("shrinkfaces: scale factor must be a positive scalar") + endif + + n = size (vertices, 2); + if (n < 2 || n > 3) + error ("shrinkfaces: only 2D and 3D patches are supported") + endif + + m = size (faces, 2); + if (m < 3) + error ("shrinkfaces: faces must consist of at least 3 vertices") + endif + # end: check input + + v = vertices(faces'(:), :); + if (isempty (colors) || size (colors, 1) == size (faces, 1)) + c = colors; + elseif (size (colors, 1) == size (vertices, 1)) + c = colors(faces'(:), :); + else + c = []; # inconsistent color data, let's discard it + endif + sv = size (v, 1); + # we have to deal with a probably very large number of vertices, so use sparse + # we use as midpoint (1/m, ..., 1/m) in generalized barycentric coordinates + midpoints = full (kron ( speye (sv / m), ones (m, m) / m) * sparse (v)); + v = sqrt (sf) * (v - midpoints) + midpoints; + f = reshape (1:sv, m, sv / m)'; + + switch nargout + case 0 + if (ishandle (p)) + set (p, "FaceVertexCData", [], "CData", []) # avoid exceptions + set (p, "Vertices", v, "Faces", f, "FaceVertexCData", c) + else + nf = struct ("faces", f, "vertices", v, "facevertexcdata", c); + endif + case 1 + nf = struct ("faces", f, "vertices", v, "facevertexcdata", c); + case 2 + nf = f; + nv = v; + endswitch +endfunction + + +%!demo +%! faces = [1 2 3; 1 3 4]; +%! vertices = [0 0; 1 0; 1 1; 0 1]; +%! clf () +%! patch ("Faces", faces, "Vertices", vertices, "FaceColor", "none") +%! fv = shrinkfaces (faces, vertices, 0.25); +%! patch (fv) +%! axis equal + +%!demo +%! faces = [1 2 3 4; 5 6 7 8]; +%! vertices = [0 0; 1 0; 2 1; 1 1; 2 0; 3 0; 4 1; 3.5 1]; +%! clf () +%! patch ("Faces", faces, "Vertices", vertices, "FaceColor", "none") +%! fv = shrinkfaces (faces, vertices, 0.25); +%! patch (fv) +%! axis equal +%! grid on + +%!demo +%! faces = [1 2 3 4]; +%! vertices = [-1 2; 0 0; 1 2; 0 1]; +%! clf () +%! patch ("Faces", faces, "Vertices", vertices, "FaceColor", "none") +%! fv = shrinkfaces (faces, vertices, 0.25); +%! patch (fv) +%! axis equal +%! grid on +%! title "faces which are not convex are clearly not allowed" + +%!demo +%! [phi r] = meshgrid (linspace (0, 1.5*pi, 16), linspace (1, 2, 4)); +%! tri = delaunay (phi(:), r(:)); +%! v = [r(:).*sin(phi(:)) r(:).*cos(phi(:))]; +%! clf () +%! p = patch ("Faces", tri, "Vertices", v, "FaceColor", "none"); +%! fv = shrinkfaces (p); +%! patch (fv) +%! axis equal +%! grid on + +%!demo +%! N = 10; # N intervals per axis +%! [x, y, z] = meshgrid (linspace (-4,4,N+1)); +%! val = x.^3 + y.^3 + z.^3; +%! fv = isosurface (x, y, z, val, 3, z); +%! +%! clf () +%! p = patch ("Faces", fv.faces, "Vertices", fv.vertices, "FaceVertexCData", ... +%! fv.facevertexcdata, "FaceColor", "interp", "EdgeColor", "black"); +%! axis equal +%! view (115, 30) +%! drawnow +%! shrinkfaces (p, 0.6); + +%!shared faces, vertices, nfv, nfv2 +%! faces = [1 2 3]; +%! vertices = [0 0 0; 1 0 0; 1 1 0]; +%! nfv = shrinkfaces (faces, vertices, 0.7); +%! nfv2 = shrinkfaces (nfv, 1/0.7); +%!assert (isfield (nfv, "faces")); +%!assert (isfield (nfv, "vertices")); +%!assert (size (nfv.faces), [1 3]); +%!assert (size (nfv.vertices), [3 3]); +%!assert (norm (nfv2.vertices - vertices), 0, 2*eps);