function [theResult, theStraightness] = rect(z, ntimes, n1, n2, n3, n4) % rect -- Map contour points onto a rectangle. % rect(z, ntimes, n1, n2, n3, n4) maps the complex z % contour points, in counter-clockwise sequence, % onto a unit-rectangle, using ntimes iterations. % The n1..n4 are the indices of the four % corner-points. % [theResult, theStraightness] = rect(...) also % returns a measure of straightness, which % should be very close to 1. Convergence can be % checked by computing the norm of the difference % of two successive iterations. % rect(n, ntimes) demonstrates itself with n random % points (default is 40) and ntimes iterations % (default is sqrt(n)). The corner-positions % are chosen randomly. % % Reference: Ives, D.D. and R.M. Zacharias, Conformal % mapping and orthogonal grid generation, Paper No. % 87-2057, AIAA/SAE/ASME/ASEE 23rd Joint Propultion % Conference, San Diego, California, June, 1987. % The present routine is modified slightly to avoid % zero-divides. % Copyright (C) 1997 Dr. Charles R. Denham, ZYDECO. % All Rights Reserved. % Disclosure without explicit written consent from the % copyright owner does not constitute publication. % Version of 05-Jun-1998 09:07:06. % Updated 20-Oct-1998 22:21:56. % Revised 26-Oct-1998 14:29:11. if nargin < 1, help(mfilename), z = 'demo'; end if isequal(z, 'demo'), z = 40; end if isstr(z), z = eval(z); end if length(z) == 1 if nargin < 2, ntimes = ceil(sqrt(z)); end if ischar(ntimes), ntimes = eval(ntimes); end n = fix((z+3)/4) .* 4; x = rand(1, n) - 0.5; y = rand(1, n) - 0.5; z = x + sqrt(-1) .* y; [a, ind] = sort(angle(z)); z = z(ind); z = z + exp(sqrt(-1).*a); z = 10 * z; if (0) nn = round([1 n/4 2*n/4 3*n/4]); else % Random corner-points. [s, index] = sort(rand(1, length(z)-1)); nn = [1 (sort(index(1:3))+1)]; end delete(get(gcf, 'Children')) subplot(1, 2, 1) plot(real(z), imag(z), '-+', real(z(nn)), imag(z(nn)), 'ro') title('Original') axis equal drawnow figure(gcf) et = 0; result = z; for iter = 1:ntimes z = result; tic [result, straightness] = rect(z, 1, nn); if ~isfinite(straightness), break, end et = et + toc; subplot(1, 2, 2) plot(real(result), imag(result), '-+', ... real(result(nn)), imag(result(nn)), 'ro') title(['Mapped by RECT: iteration #' int2str(iter)]) axis equal figure(gcf) drawnow end title(['Mapped by RECT']) disp([' ## Elapsed time: ' int2str(et) ' seconds.']) if nargout > 0 theResult = result; theStraightness = straightness; end zoomsafe s = [mfilename ' ' int2str(n) ' ' int2str(ntimes)]; set(gcf, 'ButtonDownFcn', s) return end z = z(:); if z(1) == z(end), z(end) = []; end n = length(z); if nargin < 2, ntimes = 1; end if nargin == 3 & length(n1) == 4 n4 = n1(4); n3 = n1(3); n2 = n1(2); n1 = n1(1); else if nargin < 3, n1 = 1; end if nargin < 4, n2 = n1 + fix(n/4); end if nargin < 5, n3 = n2 + fix(n/4); end if nargin < 6, n4 = n3 + fix(n/4); end end nn = [n1 n2 n3 n4]; r = zeros(size(z)); t = zeros(size(z)); track_errors = 0; for iter = 1:ntimes if ntimes > 10 disp([' ## Iterations remaining: ' int2str(ntimes-iter+1)]) end z_old = z; for i = 1:n % The big loop. if rem(n-i+1, 100) == 0 & 0 disp([' ## Remaining: ' int2str(n-i+1)]) end im = n - rem(n-i+1, n); % Index of previous point. ip = 1 + rem(i, n); % Index of next point. zd = 1; if z(ip) ~= z(i) zd = (z(im) - z(i)) ./ (z(ip) - z(i)); else zd = (z(im) - z(i)) ./ sqrt(eps); end alpha = atan2(imag(zd), real(zd)); % Current angle. if alpha < 0 alpha = alpha + 2 .* pi; elseif alpha == 0 alpha = sqrt(eps); end pwr = pi ./ alpha; % Power for pi outcome. if any(i == nn) % Corners. if z(im) ~= z(i) zd = (z(im) - z(i)) ./ abs(z(im) - z(i)); % Unit-vector. else zd = 1; end z = sqrt(-1) .* z ./ zd; pwr = pwr ./ 2; % Power for pi/2 outcome. end % Compute the unwrapped phases. j = 2:n; zd = z(rem(j+i-2, n)+1) - z(i); r(j) = abs(zd); t(j) = atan2(imag(zd), real(zd)) - 6.*pi; t = unwrap(t); temp = t(2:n).*pwr; pmax = max(temp); pmin = min(temp); if pmax ~= pmin pwr = min(pwr, 1.98 .* pi .* pwr ./ (pmax - pmin)); end z(i) = 0; z(rem(j+i-2, n)+1) = r(j).^pwr.*exp(sqrt(-1).*t(j).*pwr); zd = 1 ./ (z(n2) - z(n1)); % Possible zero-divide. z0 = z(n1); z = (z - z0) .* zd; end % Compute the straightness of the perimeter % by comparing the perimeter along the data % with the perimeter just around the corners. % The mapping may appear to be straight % without actually being rectangular. p1 = sum(abs(diff([z(nn); z(nn(1))]))); p2 = sum(abs(diff([z; z(1)]))); straightness = p1 ./ p2; % Norm of changes as measure of convergence. % The mapping may converge without actually % producing a rectangular shape. change = 2 .* norm(z - z_old) ./ norm(z + z_old); % Progress report. s = round(1000 .* straightness) ./ 10; c = round(1000 .* change) ./ 10; if nargout < 2 disp([' ## ' num2str(s) ' % straight; ' num2str(c) ' % change.']) end end if track_errors > 0 % Not ever checked. disp([' ## Tracking errors: ' int2str(track_errors)]) end if nargout > 0 theResult = z; theStraightness = straightness; else disp(z), straightness end