function [result, error_norm] = mexrect2grid(z, zrect, theCorners, theSize)

% mexrect2grid -- Orthogonal grid from RECT result via mex-files.
%  [result, error_norm] = mexrect2grid(z, zrect, theCorners, theSize)
%   produces a curvilinear orthogonal grid by interpolating the
%   complex contour z, using zrect, the result of applying the
%   conformal mapper RECT to z for theCorners (indices).  If zrect
%   is empty, the RECT routine is called to compute it.  If zrect
%   is a scalar, that number of RECT iterations will be performed.
%   The size of the w output grid (complex matrix), including the
%   perimeter, is determined by theSize.  The returned error_norm
%   is the norm of the respective laplacians.  This routine uses
%   the "mexrect" and "mexsepeli" mex-files if available; otherwise,
%   it calls the "rect" and "fps" m-files.
%  mexrect2grid(nPoints) demonstrates itself with a random z contour
%   of nPoints (default = 20).
 
% Copyright (C) 1998 Dr. Charles R. Denham, ZYDECO.
%  All Rights Reserved.
%   Disclosure without explicit written consent from the
%    copyright owner does not constitute publication.
 
% Version of 21-Oct-1998 20:50:16.
% Updated    09-Jun-1999 10:24:25.

if nargin < 1, help(mfilename), z = 'demo'; end
if isequal(z, 'demo'), z = 20; end
if ischar(z), z = eval(z); end

if length(z) == 1
	n = z;
	z = rand(n, 1) + sqrt(-1)*rand(n, 1);
	z = z - mean(z);
	a = angle(z);
	[a, i] = sort(a);
	jitter = 0.1;
	z = (1 + jitter * rand(size(a))) .* exp(sqrt(-1)*a);
	[ignore, nn] = sort(rand(1, length(z)-1));
	theCorners = sort([1 nn(1:3)+1]);
	theSize = 2*[n n];
	zrect = [];
	tic
	[w, err] = feval(mfilename, z, zrect, theCorners, ceil(theSize/2));
	disp([' ## Elapsed time: ' num2str(toc) ' seconds.'])
	if ~isempty(w)
		u = real(w); v = imag(w);
		u_err = real(err); v_err = imag(err);
		x = real(z); y = imag(z);
		x = [x; x(1)]; y = [y; y(1)];  % Make closed curve.
		u1 = u(:, 2:end-1);   % Trim the grid.
		v1 = v(:, 2:end-1);
		u2 = u(2:end-1, :).';
		v2 = v(2:end-1, :).';
		h = plot(u1, v1, 'g-', u2, v2, 'b-');
		hold on
		plot(x, y, 'r-', ...
				x(theCorners), y(theCorners), 'ro', ...
				x(theCorners(1)), y(theCorners(1)), 'r*')
		hold off
		xlabel('x'), ylabel('y')
		theCommand = [mfilename ' ( ' int2str(n) ' )'];
		title(theCommand)
		set(gcf, 'ButtonDownFcn', theCommand)
		figure(gcf)
		axis equal
		zoomsafe 0.9, zoomsafe
	end
	error_norm = [real(err) imag(err)];
	if nargout > 0
		result = w;
	else
		disp([' ## error_norm = ' sprintf('%0.4g %0.4gi', error_norm)])
	end
	return
end

% Check for mex-files "mexrect" and "mexsepeli".

hasMex = (exist('mexrect', 'file') == 3) & ...
			(exist('mexsepeli', 'file') == 3);

% If no actual "zrect" is given, apply RECT until
%  the straightness of the result deviates from
%  1.0 by no more than 0.1 percent.

if length(zrect) < 2
	if length(zrect) == 1
		ntimes = zrect;
	else
		ntimes = ceil(sqrt(length(z)));
	end
	zrect = z(:);
	tolerance = 0.001;
	for i = 1:ntimes
		if ~hasMex
			[zrect, straight] = feval('rect', zrect, 1, theCorners);
		else
			zrect = feval('mexrect', zrect, length(zrect), ...
				theCorners(1), theCorners(2), theCorners(3), theCorners(4));
			ztemp = zrect;
			ztemp(end+1) = ztemp(1);
			ctemp = theCorners;
			ctemp(end+1) = ctemp(1);
			num = sum(abs(diff(ztemp(ctemp))));
			den = sum(abs(diff(ztemp)));
			straight = num./den;
		end
		if norm(1-straight) <= tolerance, break, end
		disp([' ## RECT Iteration ' int2str(i) ...
				': straightness = ' num2str(straight*100) ' percent.'])
	end
	if norm(1-straight) > tolerance
		disp([' ## rect2grid: Conformal mapping not successful'])
		disp(['               after ' int2str(ntimes) ' iterations.'])
		if nargout > 0, result = []; error_norm = []; end
		return
	end
end

% Desired size.

if length(theSize) == 1, theSize = theSize * [1 1]; end

m = theSize(1); n = theSize(2);

% Get indices of matrix perimeter.

temp = zeros(theSize);
temp(:) = 1:prod(theSize);

ind = [];
ind = [ind; temp(1:m-1, 1)];
ind = [ind; temp(m, 1:n-1).'];
ind = [ind; temp(m:-1:2, n)];
ind = [ind; temp(1, n:-1:1).'];

% Interpolate around the "zrect" boundary
%  as a function of distance along the physical
%  boundary.

zrect = zrect(:).';
zrect(end+1) = zrect(1);

rdist = [0 cumsum(abs(diff(zrect)))];
rdist = rdist - min(rdist); rdist = rdist / max(rdist);

z = z(:).';
z(end+1) = z(1);
c = theCorners;
c(end+1) = length(z);

d = cumsum([1 m-1 n-1 m-1 n-1]);    % Corners around the matrix.

zi = zeros(size(ind));

slopeFlag = 1;

for i = 1:4
	j = c(i):c(i+1);   % Data corners.
	k = d(i):d(i+1);   % Matrix corners.
	rd = rdist(j); rd = rd - min(rd); rd = rd / max(rd);
	if i == 1
		pp = splinep(linspace(0, 1, length(rd)), rd, slopeFlag);
		rd1 = ppval(pp, linspace(0, 1, m));
		pp = splinep(rd, z(j), slopeFlag);
		zi(k) = ppval(pp, rd1);
	elseif i == 2
		pp = splinep(linspace(0, 1, length(rd)), rd, slopeFlag);
		rd2 = ppval(pp, linspace(0, 1, n));
		pp = splinep(rd, z(j), slopeFlag);
		zi(k) = ppval(pp, rd2);
	elseif i == 3
		pp = splinep(rd, z(j), slopeFlag);
		zi(k) = ppval(pp, fliplr(1 - rd1));
	elseif i == 4
		pp = splinep(rd, z(j), slopeFlag);
		zi(k) = ppval(pp, fliplr(1 - rd2));
	end
end

% Sprinkle interpolated values along the perimeter.

u = zeros(theSize); v = zeros(theSize);
u(ind) = real(zi); v(ind) = imag(zi);

% Aspect ratio of the rectangle.

if (1)
	dx = 1; dy = 1;   % Square.
else
	dx = abs(zrect(2)-zrect(1)) / m;   % Rectangle.
	dy = abs(zrect(3)-zrect(2)) / n;   % Rectangle.
end

% Solve Laplace's equation inside the boundary.

if ~hasMex
	isSlope = 0;
	u = feval('fps', u, isSlope, dx, dy);
	v = feval('fps', v, isSlope, dx, dy);
else   % Use MEXSEPELI.
	l2 = m-1;
	m2 = n-1;
	seta = rdist(c(2):c(3));
	sxi = rdist(c(1):c(2));
	[u, v] = feval('mexsepeli', u, v, l2, m2, seta, sxi);
end

w = u + sqrt(-1)*v;

if nargout > 0
	result = w;
else
	disp(w)
end

if nargout > 1
	del2_u = 4*del2(u);
	err_norm_u = norm(del2_u(2:end-1, 2:end-1));
	del2_v = 4*del2(v);
	err_norm_v = norm(del2_v(2:end-1, 2:end-1));
	error_norm = err_norm_u + sqrt(-1).*err_norm_v;
end
