{"id":100,"date":"2014-11-18T08:56:09","date_gmt":"2014-11-18T13:56:09","guid":{"rendered":"https:\/\/blogs.mathworks.com\/graphics\/?p=100"},"modified":"2014-11-18T08:57:18","modified_gmt":"2014-11-18T13:57:18","slug":"what-is-a-surface","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/graphics\/2014\/11\/18\/what-is-a-surface\/","title":{"rendered":"What is a Surface?"},"content":{"rendered":"<div class=\"content\"><h3>What is a Surface?<\/h3><p>What exactly is MATLAB doing when we say the following?<\/p><pre>surf(peaks)<\/pre><p>The answer seems obvious. We're telling MATLAB to draw a continuous surface through the points which are defined in the array which the function peaks returns. But where does that surface go in between those points? It turns out that there are some subtle issues hiding here, so let's look a bit closer.<\/p><p>We'll start with a smaller array so that we can see what's really going on.<\/p><pre class=\"codeinput\">rng(0)\r\nz = randn(5,7)\r\n<\/pre><pre class=\"codeoutput\">\r\nz =\r\n\r\n    0.5377   -1.3077   -1.3499   -0.2050    0.6715    1.0347    0.8884\r\n    1.8339   -0.4336    3.0349   -0.1241   -1.2075    0.7269   -1.1471\r\n   -2.2588    0.3426    0.7254    1.4897    0.7172   -0.3034   -1.0689\r\n    0.8622    3.5784   -0.0631    1.4090    1.6302    0.2939   -0.8095\r\n    0.3188    2.7694    0.7147    1.4172    0.4889   -0.7873   -2.9443\r\n\r\n<\/pre><p>Let's give that to surf and see what it draws.<\/p><pre class=\"codeinput\">f1 = figure;\r\nh = surf(z);\r\nh.FaceColor = <span class=\"string\">'interp'<\/span>;\r\nh.Marker = <span class=\"string\">'s'<\/span>;\r\nh.MarkerFaceColor = [.7 .2 .3];\r\nh.MarkerEdgeColor = <span class=\"string\">'none'<\/span>;\r\ntitle(<span class=\"string\">'surf'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2014\/surfexample_01.png\" alt=\"\"> <p>Those little grey squares are the values in the array z. It looks like the surface is interpolating linearly between those values. Is that actually what's happening? And is it the best choice?<\/p><p>MATLAB has a useful function named <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/interp2.html\">interp2<\/a> which will interpolate between the values in a 2D array. We can use interp2 to do the same sort of interpolation that surf is doing, but with more control over the interpolation.<\/p><p>First we'll create a high-res version of the X &amp; Y coordinates of that surface. I've just increased the resolution by a factor of 10, but you could use any number.<\/p><pre class=\"codeinput\">[n, m] = size(z);\r\n[x, y] = meshgrid(1:m,1:n);         <span class=\"comment\">% low-res grid<\/span>\r\n[x2,y2] = meshgrid(1:.1:m,1:.1:n);  <span class=\"comment\">% high-res grid<\/span>\r\n<\/pre><p>Then we'll use interp2 to interpolate the Z values up to that high-res mesh. And then we'll give that high-res array of Z values to surf.<\/p><pre class=\"codeinput\">clf(f1);\r\nz2 = interp2(x,y,z, x2,y2); <span class=\"comment\">% interpolate up<\/span>\r\nf = surf(x2,y2,z2);\r\nf.EdgeColor = <span class=\"string\">'none'<\/span>;\r\nf.FaceColor = <span class=\"string\">'interp'<\/span>;\r\nf.FaceLighting = <span class=\"string\">'gouraud'<\/span>;\r\ntitle(<span class=\"string\">'interp2'<\/span>)\r\nhold <span class=\"string\">on<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2014\/surfexample_02.png\" alt=\"\"> <p>I've turned the edges off because they would be the edges of the high-res grid. We want to add the edges of the low-res grid. We'll have to do that in two steps.<\/p><p>First the column edges.<\/p><pre class=\"codeinput\">[x3,y3] = meshgrid(1:m,1:.1:n);\r\nz3 = interp2(x,y,z, x3,y3);\r\nc = surf(x3,y3,z3);\r\nc.FaceColor = <span class=\"string\">'none'<\/span>;\r\nc.MeshStyle = <span class=\"string\">'column'<\/span>;\r\nhold <span class=\"string\">on<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2014\/surfexample_03.png\" alt=\"\"> <p>And then the row edges.<\/p><pre class=\"codeinput\">[x3,y3] = meshgrid(1:.1:m,1:n);\r\nz3 = interp2(x,y,z, x3,y3);\r\nr = surf(x3,y3,z3);\r\nr.FaceColor = <span class=\"string\">'none'<\/span>;\r\nr.MeshStyle = <span class=\"string\">'row'<\/span>;\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2014\/surfexample_04.png\" alt=\"\"> <p>And finally we'll add the markers at the original data points.<\/p><pre class=\"codeinput\">m = surf(x,y,z);\r\nm.FaceColor = <span class=\"string\">'none'<\/span>;\r\nm.MeshStyle = <span class=\"string\">'none'<\/span>;\r\nm.Marker = <span class=\"string\">'s'<\/span>;\r\nm.MarkerFaceColor = [.7 .2 .3];\r\nm.MarkerEdgeColor = <span class=\"string\">'none'<\/span>;\r\nhold <span class=\"string\">off<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2014\/surfexample_05.png\" alt=\"\"> <p>That looks pretty close to what surf did, doesn't it?<\/p><p>The interp2 function takes an argument named method that we didn't use before. We'd like to see what it looks like when we choose different values for method. We'll do that by converting those previous steps into the following function so that we can call it multiple times.<\/p><pre class=\"language-matlab\"><span class=\"keyword\">function<\/span> interpsurf(z, method)\r\n  <span class=\"keyword\">if<\/span> nargin &lt; 2\r\n    method = <span class=\"string\">'linear'<\/span>;\r\n  <span class=\"keyword\">end<\/span>\r\n  [n, m] = size(z);\r\n  [x, y] = meshgrid(1:m,1:n);         <span class=\"comment\">% low-res grid<\/span>\r\n  [x2,y2] = meshgrid(1:.1:m,1:.1:n);  <span class=\"comment\">% high-res grid<\/span>\r\n  z2 = interp2(x,y,z, x2,y2, method); <span class=\"comment\">% interpolate up<\/span>\r\n  <span class=\"comment\">% Draw the faces with no edges using the high-res grid<\/span>\r\n  f = surf(x2,y2,z2);\r\n  f.EdgeColor = <span class=\"string\">'none'<\/span>;\r\n  f.FaceColor = <span class=\"string\">'interp'<\/span>;\r\n  f.FaceLighting = <span class=\"string\">'gouraud'<\/span>;\r\n  hold <span class=\"string\">on<\/span>\r\n  <span class=\"comment\">% Add the column edges using a mix of low-res and high-res<\/span>\r\n  [x3,y3] = meshgrid(1:m,1:.1:n);\r\n  z3 = interp2(x,y,z, x3,y3, method);\r\n  c = surf(x3,y3,z3);\r\n  c.FaceColor = <span class=\"string\">'none'<\/span>;\r\n  c.MeshStyle = <span class=\"string\">'column'<\/span>;\r\n  <span class=\"comment\">% Add the row edges<\/span>\r\n  [x3,y3] = meshgrid(1:.1:m,1:n);\r\n  z3 = interp2(x,y,z, x3,y3, method);\r\n  r = surf(x3,y3,z3);\r\n  r.FaceColor = <span class=\"string\">'none'<\/span>;\r\n  r.MeshStyle = <span class=\"string\">'row'<\/span>;\r\n  <span class=\"comment\">% Add markers at the original points<\/span>\r\n  m = surf(x,y,z);\r\n  m.FaceColor = <span class=\"string\">'none'<\/span>;\r\n  m.EdgeColor = <span class=\"string\">'none'<\/span>;\r\n  m.Marker = <span class=\"string\">'s'<\/span>;\r\n  m.MarkerFaceColor = [.7 .2 .3];\r\n  m.MarkerEdgeColor = <span class=\"string\">'none'<\/span>;\r\n  hold <span class=\"string\">off<\/span>\r\n<\/pre><p>Now we can try the four different options for the method argument and compare the resulting surfaces.<\/p><pre class=\"codeinput\">f2 = figure(<span class=\"string\">'Position'<\/span>,[100 100 760 600]);\r\nsubplot(2,2,1)\r\ninterpsurf(z,<span class=\"string\">'linear'<\/span>)\r\ntitle <span class=\"string\">linear<\/span>\r\naxis <span class=\"string\">tight<\/span>\r\nsubplot(2,2,2)\r\ninterpsurf(z,<span class=\"string\">'spline'<\/span>)\r\ntitle <span class=\"string\">spline<\/span>\r\naxis <span class=\"string\">tight<\/span>\r\nsubplot(2,2,3)\r\ninterpsurf(z,<span class=\"string\">'nearest'<\/span>)\r\ntitle <span class=\"string\">nearest<\/span>\r\naxis <span class=\"string\">tight<\/span>\r\nsubplot(2,2,4)\r\ninterpsurf(z,<span class=\"string\">'cubic'<\/span>)\r\ntitle <span class=\"string\">cubic<\/span>\r\naxis <span class=\"string\">tight<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2014\/surfexample_06.png\" alt=\"\"> <p>As you can see, all of these functions pass through the original points. But they behave quite differently in between those points. That's showing the difference between the various interpolation methods.<\/p><p>The different interpolation methods have some notable characteristics.<\/p><div><ul><li>The linear and nearest methods never stick out past the original points. This is a property known as \"boundedness\".<\/li><\/ul><\/div><div><ul><li>But the linear and nearest options have sharp edges which the spline and cubic options do not have. We would say that the spline and cubic options are \"smoother\".<\/li><\/ul><\/div><div><ul><li>The differences between the spline and cubic methods are sometimes referred to as \"stiffness\".<\/li><\/ul><\/div><p>There's usually not one \"right\" choice for an interpolation function. You often need to strike a balance between boundedness, smoothness, and other characteristics of the interpolation function.<\/p><p>Of these, it looks like the linear option is the same as what surf did, but if we look closely we can see that there are actually some small differences.<\/p><p>\r\n<br\/><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2014\/surfexample_01.png\">\r\n<br\/><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2014\/surfexample_05.png\">\r\n<\/p><p>Can you spot the differences?<\/p><p>The difference is that interp2 is doing something called <a href=\"http:\/\/en.wikipedia.org\/wiki\/Bilinear_interpolation\">bilinear interpolation<\/a>, but surf is doing something called \"piecewise linear\" interpolation. These interpolation techniques are similar, but they're not quite the same.<\/p><p>The term bilinear interpolation means that it is actually the product of two linear equations. One is a linear interpolation in X.<\/p><p>$$f(x) = a_1 + a_2 x$$<\/p><p>The other equation is a linear interpolation in Y.<\/p><p>$$f(y) = b_1 + b_2 y$$<\/p><p>But the product of the two is not a linear equation. It is actually a quadratic equation which looks something like this:<\/p><p>$$f(x,y) = c_1 + c_2 x + c_3 y + c_4 x y$$<\/p><p>In the piecewise linear case, surf is actually breaking the 2x2 square into two triangles and then performing linear interpolation within the triangle using a linear equation.<\/p><p>The reason that surf uses piecewise linear is that modern graphics cards can evaluate linear equations very quickly, but they're not as good at the quadratic equation we encounter in bilinear interpolation. This means that piecewise linear has an important performance advantage over bilinear.<\/p><p>As we can see, this piecewise linear approach is very similar to the linear option. In fact, it is exactly the same as the linear option along the edges. It also has the boundedness property of the linear option. In general it's usually close enough to linear that the improved performance makes it worth using.<\/p><p>But it does have one important weakness. It is even less smooth than the linear option because it adds an extra crease along the diagonal of each 2x2 set of neighboring points where the two triangles meet. These diagonals also mean that surf's piecewise linear interpolation is <a href=\"http:\/\/en.wikipedia.org\/wiki\/Anisotropy\">anisotropic<\/a>, rather than being <a href=\"http:\/\/en.wikipedia.org\/wiki\/Isotropy\">isotropic<\/a> like the bilinear interpolation that interp2 uses. This can be important in some cases.<\/p><p>You can see one of the creases in the light blue square one up from the bottom in this picture.<\/p><pre class=\"codeinput\">delete(f2);\r\nclf(f1);\r\nsurf(z)\r\nh = light;\r\nh.Style = <span class=\"string\">'local'<\/span>;\r\nh.Position = [1.5 3 3];\r\nview(-33.5,60)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2014\/surfexample_07.png\" alt=\"\"> <p>It is important to recognize when surf's interpolation scheme is not the one which is appropriate for your purposes. When it's not, you'll want to use something like the interpsurf function we wrote today.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_231c41558de34d3da0f9d75b41c483d3() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='231c41558de34d3da0f9d75b41c483d3 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 231c41558de34d3da0f9d75b41c483d3';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2014 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_231c41558de34d3da0f9d75b41c483d3()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2014b<br><\/p><\/div><!--\r\n231c41558de34d3da0f9d75b41c483d3 ##### SOURCE BEGIN #####\r\n%% What is a Surface?\r\n% What exactly is MATLAB doing when we say the following?\r\n%\r\n%  surf(peaks)\r\n%\r\n% The answer seems obvious.\r\n% We're telling MATLAB to draw a continuous surface through the points\r\n% which are defined in the array which the function peaks returns. But\r\n% where does that surface go in between those points? It turns out that\r\n% there are some subtle issues hiding here, so let's look a bit closer.\r\n%\r\n% We'll start with a smaller array so that we can see what's really going\r\n% on.\r\nrng(0)\r\nz = randn(5,7)\r\n\r\n%%\r\n% Let's give that to surf and see what it draws.\r\nf1 = figure;\r\nh = surf(z);\r\nh.FaceColor = 'interp';\r\nh.Marker = 's';\r\nh.MarkerFaceColor = [.7 .2 .3];\r\nh.MarkerEdgeColor = 'none';\r\ntitle('surf')\r\n\r\n%%\r\n% Those little grey squares are the values in the array z. It looks like\r\n% the surface is interpolating linearly between those values. Is that\r\n% actually what's happening? And is it the best choice?\r\n%\r\n% MATLAB has a useful function named <https:\/\/www.mathworks.com\/help\/matlab\/ref\/interp2.html interp2> which will interpolate between\r\n% the values in a 2D array. We can use interp2 to do the same sort of\r\n% interpolation that surf is doing, but with more control over the\r\n% interpolation.\r\n%\r\n% First we'll create a high-res version of the X & Y coordinates of that\r\n% surface. I've just increased the resolution by a factor of 10, but you\r\n% could use any number.\r\n[n, m] = size(z);\r\n[x, y] = meshgrid(1:m,1:n);         % low-res grid \r\n[x2,y2] = meshgrid(1:.1:m,1:.1:n);  % high-res grid\r\n\r\n%%\r\n% Then we'll use interp2 to interpolate the Z values up to that high-res\r\n% mesh. And then we'll give that high-res array of Z values to surf.\r\nclf(f1);\r\nz2 = interp2(x,y,z, x2,y2); % interpolate up\r\nf = surf(x2,y2,z2);\r\nf.EdgeColor = 'none';\r\nf.FaceColor = 'interp';\r\nf.FaceLighting = 'gouraud';\r\ntitle('interp2')\r\nhold on\r\n\r\n%%\r\n% I've turned the edges off because they would be the edges of the high-res\r\n% grid. We want to add the edges of the low-res grid. We'll have to do that\r\n% in two steps.\r\n%\r\n% First the column edges.\r\n[x3,y3] = meshgrid(1:m,1:.1:n);\r\nz3 = interp2(x,y,z, x3,y3);\r\nc = surf(x3,y3,z3);\r\nc.FaceColor = 'none';\r\nc.MeshStyle = 'column';\r\nhold on\r\n\r\n%%\r\n% And then the row edges.\r\n[x3,y3] = meshgrid(1:.1:m,1:n);\r\nz3 = interp2(x,y,z, x3,y3);\r\nr = surf(x3,y3,z3);\r\nr.FaceColor = 'none';\r\nr.MeshStyle = 'row';\r\n\r\n%%\r\n% And finally we'll add the markers at the original data points.\r\nm = surf(x,y,z);\r\nm.FaceColor = 'none';\r\nm.MeshStyle = 'none';\r\nm.Marker = 's';\r\nm.MarkerFaceColor = [.7 .2 .3];\r\nm.MarkerEdgeColor = 'none';\r\nhold off\r\n\r\n%%\r\n%\r\n% That looks pretty close to what surf did, doesn't it?\r\n%\r\n% The interp2 function takes an argument named method that we didn't use \r\n% before. We'd like to see what it looks like when we choose different\r\n% values for method. We'll do that by converting those previous steps into\r\n% the following function so that we can call it multiple times.\r\n%\r\n%   function interpsurf(z, method)\r\n%     if nargin < 2\r\n%       method = 'linear';\r\n%     end\r\n%     [n, m] = size(z);\r\n%     [x, y] = meshgrid(1:m,1:n);         % low-res grid \r\n%     [x2,y2] = meshgrid(1:.1:m,1:.1:n);  % high-res grid\r\n%     z2 = interp2(x,y,z, x2,y2, method); % interpolate up\r\n%     % Draw the faces with no edges using the high-res grid\r\n%     f = surf(x2,y2,z2);\r\n%     f.EdgeColor = 'none';\r\n%     f.FaceColor = 'interp';\r\n%     f.FaceLighting = 'gouraud';\r\n%     hold on\r\n%     % Add the column edges using a mix of low-res and high-res\r\n%     [x3,y3] = meshgrid(1:m,1:.1:n);\r\n%     z3 = interp2(x,y,z, x3,y3, method);\r\n%     c = surf(x3,y3,z3);\r\n%     c.FaceColor = 'none';\r\n%     c.MeshStyle = 'column';\r\n%     % Add the row edges\r\n%     [x3,y3] = meshgrid(1:.1:m,1:n);\r\n%     z3 = interp2(x,y,z, x3,y3, method);\r\n%     r = surf(x3,y3,z3);\r\n%     r.FaceColor = 'none';\r\n%     r.MeshStyle = 'row';\r\n%     % Add markers at the original points\r\n%     m = surf(x,y,z);\r\n%     m.FaceColor = 'none';\r\n%     m.EdgeColor = 'none';\r\n%     m.Marker = 's';\r\n%     m.MarkerFaceColor = [.7 .2 .3];\r\n%     m.MarkerEdgeColor = 'none';\r\n%     hold off\r\n%\r\n% Now we can try the four different options for the method argument and\r\n% compare the resulting surfaces.\r\n%\r\nf2 = figure('Position',[100 100 760 600]);\r\nsubplot(2,2,1)\r\ninterpsurf(z,'linear')\r\ntitle linear\r\naxis tight\r\nsubplot(2,2,2)\r\ninterpsurf(z,'spline')\r\ntitle spline\r\naxis tight\r\nsubplot(2,2,3)\r\ninterpsurf(z,'nearest')\r\ntitle nearest\r\naxis tight\r\nsubplot(2,2,4)\r\ninterpsurf(z,'cubic')\r\ntitle cubic\r\naxis tight\r\n\r\n%%\r\n% As you can see, all of these functions pass through the original points.\r\n% But they behave quite differently in between those points. That's showing\r\n% the difference between the various interpolation methods.\r\n%\r\n% The different interpolation methods have some notable characteristics.\r\n%\r\n% * The linear and nearest methods never stick out past the original points.\r\n% This is a property known as \"boundedness\".\r\n%\r\n% * But the linear and nearest options have sharp edges which the spline and\r\n% cubic options do not have. We would say that the spline and cubic options are\r\n% \"smoother\".\r\n%\r\n% * The differences between the spline and cubic methods are sometimes\r\n% referred to as \"stiffness\".\r\n% \r\n% There's usually not one \"right\" choice for an interpolation function. You\r\n% often need to strike a balance between boundedness, smoothness, and other\r\n% characteristics of the interpolation function.\r\n%\r\n% Of these, it looks like the linear option is the same as what surf did,\r\n% but if we look closely we can see that there are actually some small\r\n% differences.\r\n%\r\n% <img decoding=\"async\" src=\"surfexample_01.png\">\r\n%\r\n% <img decoding=\"async\" src=\"surfexample_05.png\">\r\n%\r\n% Can you spot the differences?\r\n%\r\n% The difference is that interp2 is doing something called \r\n% <http:\/\/en.wikipedia.org\/wiki\/Bilinear_interpolation bilinear interpolation>, \r\n% but surf is doing something called \"piecewise linear\" interpolation. \r\n% These interpolation techniques are similar, but they're not quite the same.\r\n%\r\n% The term bilinear interpolation means that it is actually the product of\r\n% two linear equations. One is a linear interpolation in X.\r\n%\r\n% $$f(x) = a_1 + a_2 x$$\r\n% \r\n% The other equation is a linear interpolation in Y. \r\n%\r\n% $$f(y) = b_1 + b_2 y$$\r\n%\r\n% But the product of the two is not a linear equation. It is actually a \r\n% quadratic equation which looks something like this:\r\n%\r\n% $$f(x,y) = c_1 + c_2 x + c_3 y + c_4 x y$$\r\n%\r\n% In the piecewise linear case, surf is actually breaking the 2x2 square\r\n% into two triangles and then performing linear interpolation within the\r\n% triangle using a linear equation.\r\n%\r\n% The reason that surf uses piecewise linear is that modern graphics cards\r\n% can evaluate linear equations very quickly, but they're not as good at\r\n% the quadratic equation we encounter in bilinear interpolation. This means that\r\n% piecewise linear has an important performance advantage over bilinear.\r\n% \r\n% As we can see, this piecewise linear approach is very similar to the \r\n% linear option. In fact, it is exactly the same as the linear option along \r\n% the edges. It also has the boundedness property of the linear option. In \r\n% general it's usually close enough to linear that the improved performance\r\n% makes it worth using. \r\n%\r\n% But it does have one important weakness. It is even less smooth than the \r\n% linear option because it adds an extra crease along the diagonal of each \r\n% 2x2 set of neighboring points where the two triangles meet. These diagonals \r\n% also mean that surf's piecewise linear interpolation is\r\n% <http:\/\/en.wikipedia.org\/wiki\/Anisotropy anisotropic>, rather than being \r\n% <http:\/\/en.wikipedia.org\/wiki\/Isotropy isotropic> like the bilinear interpolation\r\n% that interp2 uses. This can be important in some cases.\r\n%\r\n% You can see one of the creases in the light blue square one up from the\r\n% bottom in this picture.\r\ndelete(f2);\r\nclf(f1);\r\nsurf(z)\r\nh = light;\r\nh.Style = 'local';\r\nh.Position = [1.5 3 3];\r\nview(-33.5,60)\r\n\r\n%%\r\n% It is important to recognize when surf's interpolation scheme is not the \r\n% one which is appropriate for your purposes. When it's not, you'll want \r\n% to use something like the interpsurf function we wrote today.\r\n\r\n##### SOURCE END ##### 231c41558de34d3da0f9d75b41c483d3\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/graphics\/files\/feature_image\/surfexample_05.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>What is a Surface?What exactly is MATLAB doing when we say the following?surf(peaks)The answer seems obvious. We're telling MATLAB to draw a continuous surface through the points which are defined in... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/graphics\/2014\/11\/18\/what-is-a-surface\/\">read more >><\/a><\/p>","protected":false},"author":89,"featured_media":113,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/100"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/users\/89"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/comments?post=100"}],"version-history":[{"count":13,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/100\/revisions"}],"predecessor-version":[{"id":114,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/100\/revisions\/114"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media\/113"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media?parent=100"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/categories?post=100"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/tags?post=100"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}