14574
|
1 ## Copyright (C) 2012 Martin Helm |
|
2 ## |
|
3 ## This file is part of Octave. |
|
4 ## |
|
5 ## Octave is free software; you can redistribute it and/or modify it |
|
6 ## under the terms of the GNU General Public License as published by |
|
7 ## the Free Software Foundation; either version 3 of the License, or (at |
|
8 ## your option) any later version. |
|
9 ## |
|
10 ## Octave is distributed in the hope that it will be useful, but |
|
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 ## General Public License for more details. |
|
14 ## |
|
15 ## You should have received a copy of the GNU General Public License |
|
16 ## along with Octave; see the file COPYING. If not, see |
|
17 ## <http://www.gnu.org/licenses/>. |
|
18 |
|
19 ## -*- texinfo -*- |
|
20 ## @deftypefn {Function File} {} shrinkfaces (@var{p}, @var{sf}) |
|
21 ## @deftypefnx {Function File} {@var{nfv} =} shrinkfaces (@var{p}, @var{sf}) |
|
22 ## @deftypefnx {Function File} {@var{nfv} =} shrinkfaces (@var{fv}, @var{sf}) |
|
23 ## @deftypefnx {Function File} {@var{nfv} =} shrinkfaces (@var{f}, @var{v}, @var{sf}) |
|
24 ## @deftypefnx {Function File} {[@var{nf}, @var{nv}] =} shrinkfaces (@dots{}) |
|
25 ## |
|
26 ## Reduce the faces area for a given patch, structure or explicit faces |
|
27 ## and points matrices by a scale factor @var{sf}. The structure |
|
28 ## @var{fv} must contain the fields 'faces' and 'vertices'. If the |
|
29 ## factor @var{sf} is omitted then a default of 0.3 is used. |
|
30 ## |
|
31 ## Given a patch handle as the first input argument and no output |
|
32 ## parameters, perform the shrinking of the patch faces in place and |
|
33 ## redraw the patch. |
|
34 ## |
|
35 ## If called with one output argument, return a structure with fields |
|
36 ## 'faces', 'vertices', and 'facevertexcdata' containing the data after |
|
37 ## shrinking which can then directly be used as an input argument for the |
|
38 ## @command{patch} function. |
|
39 ## |
|
40 ## Performing the shrinking on faces which are not convex can lead to |
|
41 ## undesired results. |
|
42 ## |
|
43 ## For example |
|
44 ## |
|
45 ## @example |
|
46 ## @group |
|
47 ## [phi r] = meshgrid (linspace (0, 1.5*pi, 16), linspace (1, 2, 4)); |
|
48 ## tri = delaunay (phi(:), r(:)); |
|
49 ## v = [r(:).*sin(phi(:)) r(:).*cos(phi(:))]; |
|
50 ## clf () |
|
51 ## p = patch ("Faces", tri, "Vertices", v, "FaceColor", "none"); |
|
52 ## fv = shrinkfaces (p); |
|
53 ## patch (fv) |
|
54 ## axis equal |
|
55 ## grid on |
|
56 ## @end group |
|
57 ## @end example |
|
58 ## |
|
59 ## @noindent |
|
60 ## draws a triangulated 3/4 circle and the corresponding shrinked |
|
61 ## version. |
|
62 ## @seealso{patch} |
|
63 ## @end deftypefn |
|
64 |
|
65 ## Author: Martin Helm <martin@mhelm.de> |
|
66 |
|
67 function [nf, nv] = shrinkfaces (varargin) |
|
68 |
|
69 if (nargin < 1 || nargin > 3 || nargout > 2) |
|
70 print_usage (); |
|
71 endif |
|
72 |
|
73 sf = 0.3; |
|
74 p = varargin{1}; |
|
75 colors = []; |
|
76 |
|
77 if (ishandle (p) && nargin < 3) |
|
78 faces = get (p, "Faces"); |
|
79 vertices = get (p, "Vertices"); |
|
80 colors = get (p, "FaceVertexCData"); |
|
81 if (nargin == 2) |
|
82 sf = varargin{2}; |
|
83 endif |
|
84 elseif (isstruct (p) && nargin < 3) |
|
85 faces = p.faces; |
|
86 vertices = p.vertices; |
|
87 if (isfield (p, "facevertexcdata")) |
|
88 colors = p.facevertexcdata; |
|
89 endif |
|
90 if (nargin == 2) |
|
91 sf = varargin{2}; |
|
92 endif |
|
93 elseif (ismatrix (p) && nargin >= 2 && ismatrix (varargin{2})) |
|
94 faces = p; |
|
95 vertices = varargin{2}; |
|
96 if (nargin == 3) |
|
97 sf = varargin{3}; |
|
98 endif |
|
99 else |
|
100 print_usage (); |
|
101 endif |
|
102 |
|
103 if (! isscalar (sf) || sf <= 0) |
|
104 error ("shrinkfaces: scale factor must be a positive scalar") |
|
105 endif |
|
106 |
|
107 n = size (vertices, 2); |
|
108 if (n < 2 || n > 3) |
|
109 error ("shrinkfaces: only 2D and 3D patches are supported") |
|
110 endif |
|
111 |
|
112 m = size (faces, 2); |
|
113 if (m < 3) |
|
114 error ("shrinkfaces: faces must consist of at least 3 vertices") |
|
115 endif |
|
116 |
|
117 v = vertices(faces'(:), :); |
|
118 if (isempty (colors) || size (colors, 1) == size (faces, 1)) |
|
119 c = colors; |
|
120 elseif (size (colors, 1) == size (vertices, 1)) |
|
121 c = colors(faces'(:), :); |
|
122 else |
|
123 ## Discard inconsistent color data. |
|
124 c = []; |
|
125 endif |
|
126 sv = size (v, 1); |
|
127 ## we have to deal with a probably very large number of vertices, so |
|
128 ## use sparse we use as midpoint (1/m, ..., 1/m) in generalized |
|
129 ## barycentric coordinates. |
|
130 midpoints = full (kron ( speye (sv / m), ones (m, m) / m) * sparse (v)); |
|
131 v = sqrt (sf) * (v - midpoints) + midpoints; |
|
132 f = reshape (1:sv, m, sv / m)'; |
|
133 |
|
134 switch (nargout) |
|
135 case 0 |
|
136 if (ishandle (p)) |
|
137 set (p, "FaceVertexCData", [], "CData", []) # avoid exceptions |
|
138 set (p, "Vertices", v, "Faces", f, "FaceVertexCData", c) |
|
139 else |
|
140 nf = struct ("faces", f, "vertices", v, "facevertexcdata", c); |
|
141 endif |
|
142 case 1 |
|
143 nf = struct ("faces", f, "vertices", v, "facevertexcdata", c); |
|
144 case 2 |
|
145 nf = f; |
|
146 nv = v; |
|
147 endswitch |
|
148 |
|
149 endfunction |
|
150 |
|
151 %!demo |
|
152 %! faces = [1 2 3; 1 3 4]; |
|
153 %! vertices = [0 0; 1 0; 1 1; 0 1]; |
|
154 %! clf () |
|
155 %! patch ("Faces", faces, "Vertices", vertices, "FaceColor", "none") |
|
156 %! fv = shrinkfaces (faces, vertices, 0.25); |
|
157 %! patch (fv) |
|
158 %! axis equal |
|
159 |
|
160 %!demo |
|
161 %! faces = [1 2 3 4; 5 6 7 8]; |
|
162 %! vertices = [0 0; 1 0; 2 1; 1 1; 2 0; 3 0; 4 1; 3.5 1]; |
|
163 %! clf () |
|
164 %! patch ("Faces", faces, "Vertices", vertices, "FaceColor", "none") |
|
165 %! fv = shrinkfaces (faces, vertices, 0.25); |
|
166 %! patch (fv) |
|
167 %! axis equal |
|
168 %! grid on |
|
169 |
|
170 %!demo |
|
171 %! faces = [1 2 3 4]; |
|
172 %! vertices = [-1 2; 0 0; 1 2; 0 1]; |
|
173 %! clf () |
|
174 %! patch ("Faces", faces, "Vertices", vertices, "FaceColor", "none") |
|
175 %! fv = shrinkfaces (faces, vertices, 0.25); |
|
176 %! patch (fv) |
|
177 %! axis equal |
|
178 %! grid on |
|
179 %! title "faces which are not convex are clearly not allowed" |
|
180 |
|
181 %!demo |
|
182 %! [phi r] = meshgrid (linspace (0, 1.5*pi, 16), linspace (1, 2, 4)); |
|
183 %! tri = delaunay (phi(:), r(:)); |
|
184 %! v = [r(:).*sin(phi(:)) r(:).*cos(phi(:))]; |
|
185 %! clf () |
|
186 %! p = patch ("Faces", tri, "Vertices", v, "FaceColor", "none"); |
|
187 %! fv = shrinkfaces (p); |
|
188 %! patch (fv) |
|
189 %! axis equal |
|
190 %! grid on |
|
191 |
|
192 %!demo |
|
193 %! N = 10; # N intervals per axis |
|
194 %! [x, y, z] = meshgrid (linspace (-4,4,N+1)); |
|
195 %! val = x.^3 + y.^3 + z.^3; |
|
196 %! fv = isosurface (x, y, z, val, 3, z); |
|
197 %! |
|
198 %! clf () |
|
199 %! p = patch ("Faces", fv.faces, "Vertices", fv.vertices, "FaceVertexCData", ... |
|
200 %! fv.facevertexcdata, "FaceColor", "interp", "EdgeColor", "black"); |
|
201 %! axis equal |
|
202 %! view (115, 30) |
|
203 %! drawnow |
|
204 %! shrinkfaces (p, 0.6); |
|
205 |
|
206 %!shared faces, vertices, nfv, nfv2 |
|
207 %! faces = [1 2 3]; |
|
208 %! vertices = [0 0 0; 1 0 0; 1 1 0]; |
|
209 %! nfv = shrinkfaces (faces, vertices, 0.7); |
|
210 %! nfv2 = shrinkfaces (nfv, 1/0.7); |
|
211 %!assert (isfield (nfv, "faces")); |
|
212 %!assert (isfield (nfv, "vertices")); |
|
213 %!assert (size (nfv.faces), [1 3]); |
|
214 %!assert (size (nfv.vertices), [3 3]); |
|
215 %!assert (norm (nfv2.vertices - vertices), 0, 2*eps); |