{"id":239,"date":"2015-05-12T09:49:20","date_gmt":"2015-05-12T13:49:20","guid":{"rendered":"https:\/\/blogs.mathworks.com\/graphics\/?p=239"},"modified":"2015-05-12T09:53:08","modified_gmt":"2015-05-12T13:53:08","slug":"patch-work","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/graphics\/2015\/05\/12\/patch-work\/","title":{"rendered":"Patch Work"},"content":{"rendered":"<div class=\"content\"><h3>Patch Work<\/h3><p>Back before the internet, programmers collected xeroxed copies of old notes and papers. We traded these with our friends and coworkers, like <a href=\"http:\/\/en.wikipedia.org\/wiki\/Samizdat\">samizdat<\/a>. I still have a large filing cabinet full of these.<\/p><p>One of my favorites is:<\/p><p>\r\n<pre>\r\n  Patch Work\r\n  Rob Cook\r\n  Technical Memo #118\r\n  Computer Division\r\n  Lucasfilm Ltd\r\n<\/pre>\r\n<\/p><p>You can find some of the other old Lucasfilm technical memos in <a href=\"http:\/\/graphics.pixar.com\/library\/indexAuthorRobert_L_Cook.html\">Pixar's library<\/a>. But as far as I know, this one has never appeared on the internet.<\/p><p>The \"Patch Work\" memo was a collection of useful tidbits about the different types of patches which were used for representing smooth surfaces. Rob collected these from work that had been done by <a href=\"http:\/\/en.wikipedia.org\/wiki\/Loren_Carpenter\">Loren Carpenter<\/a>, <a href=\"http:\/\/en.wikipedia.org\/wiki\/Edwin_Catmull\">Ed Catmull<\/a>, and <a href=\"http:\/\/en.wikipedia.org\/wiki\/Tom_Duff\">Tom Duff<\/a>. If you worked with surface patches, it was really handy to have a single, short memo with all of this useful information collected in one place. That made this one of the more valuable graphics samizdats.<\/p><p>Let's take a quick look at some of what's in this wonderful old memo.<\/p><p>First we'll need some control points. All of these patches need a 4x4 matrix of control points. To make it easy to see what's going on, I'm going to spread these points out evenly in X &amp; Y and give them different Z values, but you can use any points you like.<\/p><pre class=\"codeinput\">[px, py] = meshgrid(1:4);\r\npz = magic(4) \/ 8;\r\n<\/pre><p>First we'll draw them using stem3.<\/p><pre class=\"codeinput\">p = stem3(px,py,pz,<span class=\"string\">'filled'<\/span>);\r\ndaspect([1 1 1])\r\nax = gca;\r\nax.XTick = 1:4;\r\nax.YTick = 1:4;\r\ncolor = [.15 .15 .15];\r\np.Color = color;\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_01.png\" alt=\"\"> <p>We can connect them into their 4x4  grid by using a surface with FaceColor='none'.<\/p><pre class=\"codeinput\">hold <span class=\"string\">on<\/span>\r\ncpts = surf(px,py,pz);\r\ncpts.FaceColor = <span class=\"string\">'none'<\/span>;\r\ncpts.EdgeColor = [.85 .85 .85];\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_02.png\" alt=\"\"> <p>Now we're ready to create some patches. All of the patches take the same form. A pair of parameter values u &amp; v yield a point when they're substituted into the following equation.<\/p><p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_eq15081982801253890923.png\" alt=\"$$x = \\left(\\begin{array}{cccc}v^3 v^2 v 1\\end{array}\\right) MPM^T \\left(\\begin{array}{c}u^3 \\\\ u^2 \\\\ u \\\\ 1\\end{array}\\right)$$\"><\/p><p>In this equation, the matrix P is our 4x4 matrix of control points, and the matrix M is called the \"basis matrix\" of the patch. The memo covers several different basis matrices, starting with our old favorite, the cubic <a href=\"http:\/\/en.wikipedia.org\/wiki\/B%C3%A9zier_surface\">B&eacute;zier patch<\/a>. This is the patch that we saw in <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2014\/10\/03\/welcome\/\">my first blog post here<\/a> when we were looking at Newell's teapot. You'll also notice the similarities to the equation for the cubic B&eacute;zier curve we saw in <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2014\/10\/13\/bezier-curves\/\">my second post<\/a>.<\/p><pre class=\"codeinput\">Mbezier = [-1  3 -3 1; <span class=\"keyword\">...<\/span>\r\n            3 -6  3 0; <span class=\"keyword\">...<\/span>\r\n           -3  3  0 0; <span class=\"keyword\">...<\/span>\r\n            1  0  0 0];\r\n<\/pre><p>We can use that to generate a surface with one set of isoparameter lines like this:<\/p><pre class=\"codeinput\">M = Mbezier;\r\n\r\n<span class=\"comment\">% U &amp; V vectors<\/span>\r\nu = linspace(0,1,50);\r\nv = linspace(0,1,50)';\r\nu_powers = [u.^3; u.^2; u; ones(size(u))];\r\nv_powers = [v.^3, v.^2, v, ones(size(v))];\r\n\r\n<span class=\"comment\">% Multiply to get X,Y, &amp; Z<\/span>\r\nxout = v_powers * M * px * M' * u_powers;\r\nyout = v_powers * M * py * M' * u_powers;\r\nzout = v_powers * M * pz * M' * u_powers;\r\n\r\n<span class=\"comment\">% Draw as a surface<\/span>\r\nhold <span class=\"string\">on<\/span>\r\ns = surf(xout,yout,zout);\r\ns.FaceColor = <span class=\"string\">'none'<\/span>;\r\ns.MeshStyle = <span class=\"string\">'row'<\/span>;\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_03.png\" alt=\"\"> <p>And then the show the other set of isoparameter lines like this:<\/p><pre class=\"codeinput\">s.MeshStyle = <span class=\"string\">'column'<\/span>;\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_04.png\" alt=\"\"> <p>or as a shaded surface with lighting.<\/p><pre class=\"codeinput\">s.EdgeColor = <span class=\"string\">'none'<\/span>;\r\ns.FaceColor = <span class=\"string\">'interp'<\/span>;\r\ns.FaceLighting = <span class=\"string\">'gouraud'<\/span>;\r\ns.SpecularStrength = 5\/8;\r\nlight(<span class=\"string\">'Position'<\/span>,[9 -5 8])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_05.png\" alt=\"\"> <p>A coarser colormap will add \"waterlevel\" lines.<\/p><pre class=\"codeinput\">colormap(lines(20))\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_06.png\" alt=\"\"> <p>Notice that the B&eacute;zier patch has the same characteristics we saw in the earlier blog post about the curves. It passes through the 4 control points in the corners of the 4x4 set, it's tangent to the control point mesh at those corners, and it's completely contained within the bounds of the control point mesh. These are really useful properties and they make B&eacute;zier very easy to work with.<\/p><p>The \"Patch Work\" memo includes the basis matrices for a number of other types of patches, but some of them are a little trickier to work with.<\/p><p>Let's try the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Centripetal_Catmull%E2%80%93Rom_spline\">Catmull-Rom<\/a> patch.<\/p><pre class=\"codeinput\">Mcatmullrom = [-1  3 -3  1; <span class=\"keyword\">...<\/span>\r\n                2 -5  4 -1; <span class=\"keyword\">...<\/span>\r\n               -1  0  1  0; <span class=\"keyword\">...<\/span>\r\n                0  2  0  0] \/ 2;\r\nM = Mcatmullrom;\r\ns.XData = v_powers * M * px * M' * u_powers;\r\ns.YData = v_powers * M * py * M' * u_powers;\r\ns.ZData = v_powers * M * pz * M' * u_powers;\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_07.png\" alt=\"\"> <p>It's a little hard to see from that viewing angle, but the way a Catmull-Rom spline works is that it connects the inner 2x2 points of our control point mesh.<\/p><pre class=\"codeinput\">view(-37.5,60)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_08.png\" alt=\"\"> <p>The other points in the control mesh of a Catmull-Rom patch simply control the tangents at the edges of the patch. The way you usually use these is to have two rows of control points be shared between neighboring patches. This ensures that the patches have a nice, smooth blend where they meet. It is possible to get the same effect with B&eacute;zier patches, but it is a little bit trickier.<\/p><p>The basis matrix for the B-spline patch looks like this.<\/p><pre class=\"codeinput\">Mbspline = [-1  3 -3 1; <span class=\"keyword\">...<\/span>\r\n             3 -6  3 0; <span class=\"keyword\">...<\/span>\r\n            -3  0  3 0; <span class=\"keyword\">...<\/span>\r\n             1  4  1 0] \/ 6;\r\nM = Mbspline;\r\ns.XData = v_powers * M * px * M' * u_powers;\r\ns.YData = v_powers * M * py * M' * u_powers;\r\ns.ZData = v_powers * M * pz * M' * u_powers;\r\nview(3)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_09.png\" alt=\"\"> <p>You can see that this patch also only covers the inner 2x2 of our control point mesh, and it doesn't even pass through those points. This property makes the B-spline patch kind of challenging to work with when you're trying to model something.<\/p><p>But the \"patch work\" memo also shows how to convert the control points of one kind of patch to those of another kind of patch. To do this, we need what it calls \"to-from\" matrices. We can use this to convert our friendly B&eacute;zier patch control points into ones which work for the B-spline patch by using this matrix.<\/p><pre class=\"codeinput\">Mtofrom = [6 -7  2 0; <span class=\"keyword\">...<\/span>\r\n           0  2 -1 0; <span class=\"keyword\">...<\/span>\r\n           0 -1  2 0; <span class=\"keyword\">...<\/span>\r\n           0  2 -7 6];\r\n\r\npxnew = Mtofrom * px * Mtofrom';\r\npynew = Mtofrom * py * Mtofrom';\r\npznew = Mtofrom * pz * Mtofrom';\r\n<\/pre><p>If we compare the control points before and after this transformation, we can see that the ones for the B-spline patch extand way outside the ones for the B&eacute;zier patch, and the Z range is much wider.<\/p><pre class=\"codeinput\">f2 = figure;\r\np1 = stem3(px,py,pz,<span class=\"string\">'filled'<\/span>);\r\nhold <span class=\"string\">on<\/span>\r\np2 = stem3(pxnew,pynew,pznew,<span class=\"string\">'filled'<\/span>);\r\nsurf(pxnew,pynew,pznew,<span class=\"string\">'FaceColor'<\/span>,<span class=\"string\">'none'<\/span>,<span class=\"string\">'EdgeColor'<\/span>,[.85 .85 .85])\r\nxlim([-inf inf])\r\nylim([-inf inf])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_10.png\" alt=\"\"> <p>But when we use these new points with the basis matrix for the B-spline patch, they will give us the same surface we got with the B&eacute;zier patch using the original control points.<\/p><pre class=\"codeinput\">delete(f2)\r\ns.XData = v_powers * M * pxnew * M' * u_powers;\r\ns.YData = v_powers * M * pynew * M' * u_powers;\r\ns.ZData = v_powers * M * pznew * M' * u_powers;\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_11.png\" alt=\"\"> <p>Being able to convert between different patch types is extremely useful because the different types have different properties which are useful in different situations.<\/p><p>You can find all of the to-from matrices in <a href=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_details.m\">this file<\/a>.<\/p><p>But there are more goodies hiding in this memo. We saw when we talked about <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2014\/12\/04\/tie-a-ribbon-round-it-parametric-curves-part-1\/\">parametric curves<\/a> that being able to compute partial derivatives of the curves is very useful for creating tangents and normals. The same is true when you're working with surface patches, and this memo has a section on how to compute partial derivatives of the patches. To compute those, we need the following two matrices.<\/p><pre class=\"codeinput\">du = [0 3 0 0; <span class=\"keyword\">...<\/span>\r\n      0 0 2 0; <span class=\"keyword\">...<\/span>\r\n      0 0 0 1; <span class=\"keyword\">...<\/span>\r\n      0 0 0 0];\r\n\r\ndv = [0 0 0 0; <span class=\"keyword\">...<\/span>\r\n      3 0 0 0; <span class=\"keyword\">...<\/span>\r\n      0 2 0 0; <span class=\"keyword\">...<\/span>\r\n      0 0 1 0];\r\n<\/pre><p>We'll create a low-res parameterization.<\/p><pre class=\"codeinput\">M = Mbezier;\r\nu = linspace(0,1,10);\r\nv = linspace(0,1,10)';\r\nu_powers = [u.^3; u.^2; u; ones(size(u))];\r\nv_powers = [v.^3, v.^2, v, ones(size(v))];\r\n\r\nxout = v_powers * M * px * M' * u_powers;\r\nyout = v_powers * M * py * M' * u_powers;\r\nzout = v_powers * M * pz * M' * u_powers;\r\n<\/pre><p>And then we use the matrices du and dv like this:<\/p><pre class=\"codeinput\">dxdu = v_powers * M * px * M' * du * u_powers;\r\ndydu = v_powers * M * py * M' * du * u_powers;\r\ndzdu = v_powers * M * pz * M' * du * u_powers;\r\ndxdv = v_powers * dv * M * px * M' * u_powers;\r\ndydv = v_powers * dv * M * py * M' * u_powers;\r\ndzdv = v_powers * dv * M * pz * M' * u_powers;\r\n<\/pre><p>We could use the cross product of those two vectors to compute normals which are much smoother than what the surface command can create. Or we can use them directly to cover the surface with a bunch of tangent circles like this:<\/p><pre class=\"codeinput\">xlim <span class=\"string\">manual<\/span>\r\nylim <span class=\"string\">manual<\/span>\r\nzlim <span class=\"string\">manual<\/span>\r\ndelete(s)\r\nradius = .05;\r\ntheta = linspace(0,2*pi,72); <span class=\"comment\">% points around the circles<\/span>\r\n<span class=\"keyword\">for<\/span> i=1:numel(xout)\r\n    <span class=\"comment\">% c + r*(cos(theta)*dp\/du + sin(theta)*dp\/dv)<\/span>\r\n    cx = xout(i) + radius*(cos(theta)*dxdu(i) + sin(theta)*dxdv(i));\r\n    cy = yout(i) + radius*(cos(theta)*dydu(i) + sin(theta)*dydv(i));\r\n    cz = zout(i) + radius*(cos(theta)*dzdu(i) + sin(theta)*dzdv(i));\r\n    h = patch(cx,cy,cz,zeros(size(cx)));\r\n    h.FaceColor = [.875 .875 .875];\r\n    h.EdgeColor = <span class=\"string\">'none'<\/span>;\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_12.png\" alt=\"\"> <p>Can you combine this with what we did in the <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2014\/10\/03\/welcome\/\">teapot blog post<\/a> to create a picture that looks like this?<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/disk_teapot.png\" alt=\"\"> <\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_4f1e2b9a0e794e95b0ca7bd46684dee5() {\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='4f1e2b9a0e794e95b0ca7bd46684dee5 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 4f1e2b9a0e794e95b0ca7bd46684dee5';\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 2015 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_4f1e2b9a0e794e95b0ca7bd46684dee5()\"><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; R2015a<br><\/p><\/div><!--\r\n4f1e2b9a0e794e95b0ca7bd46684dee5 ##### SOURCE BEGIN #####\r\n%% Patch Work\r\n% Back before the internet, programmers collected xeroxed copies of old\r\n% notes and papers. We traded these with our friends and coworkers, like \r\n% <http:\/\/en.wikipedia.org\/wiki\/Samizdat samizdat>. I still have a large \r\n% filing cabinet full of these. \r\n%\r\n% One of my favorites is:\r\n%\r\n% <html>\r\n% <pre>\r\n%   Patch Work\r\n%   Rob Cook\r\n%   Technical Memo #118\r\n%   Computer Division\r\n%   Lucasfilm Ltd\r\n% <\/pre>\r\n% <\/html>\r\n%\r\n% You can find some of the other old Lucasfilm technical memos in \r\n% <http:\/\/graphics.pixar.com\/library\/indexAuthorRobert_L_Cook.html Pixar's library>.\r\n% But as far as I know, this one has never appeared on the internet.\r\n%\r\n% The \"Patch Work\" memo was a collection of useful tidbits about the different \r\n% types of patches which were used for representing smooth surfaces. Rob collected \r\n% these from work that had been done by <http:\/\/en.wikipedia.org\/wiki\/Loren_Carpenter Loren Carpenter>, \r\n% <http:\/\/en.wikipedia.org\/wiki\/Edwin_Catmull Ed Catmull>, and <http:\/\/en.wikipedia.org\/wiki\/Tom_Duff Tom Duff>.\r\n% If you worked with surface patches, it was really handy to have a single, \r\n% short memo with all of this useful information collected in one place.\r\n% That made this one of the more valuable graphics samizdats.\r\n%\r\n% Let's take a quick look at some of what's in this wonderful old memo.\r\n%\r\n% First we'll need some control points. All of these patches need a 4x4\r\n% matrix of control points. To make it easy to see what's going on, I'm\r\n% going to spread these points out evenly in X & Y and give them different\r\n% Z values, but you can use any points you like.\r\n%\r\n[px, py] = meshgrid(1:4);\r\npz = magic(4) \/ 8;\r\n\r\n%%\r\n% First we'll draw them using stem3.\r\np = stem3(px,py,pz,'filled');\r\ndaspect([1 1 1])\r\nax = gca;\r\nax.XTick = 1:4;\r\nax.YTick = 1:4;\r\ncolor = [.15 .15 .15];\r\np.Color = color;\r\n\r\n%%\r\n% We can connect them into their 4x4  grid by using a surface with FaceColor='none'.\r\nhold on\r\ncpts = surf(px,py,pz);\r\ncpts.FaceColor = 'none';\r\ncpts.EdgeColor = [.85 .85 .85];\r\n\r\n%%\r\n% Now we're ready to create some patches. All of the patches take the same\r\n% form. A pair of parameter values u & v yield a point when they're\r\n% substituted into the following equation.\r\n%\r\n% $$x = \\left(\\begin{array}{cccc}v^3 v^2 v 1\\end{array}\\right) MPM^T \\left(\\begin{array}{c}u^3 \\\\ u^2 \\\\ u \\\\ 1\\end{array}\\right)$$\r\n%\r\n% In this equation, the matrix P is our 4x4 matrix of control points, and\r\n% the matrix M is called the \"basis matrix\" of the patch. The memo covers\r\n% several different basis matrices, starting with our old favorite, the\r\n% cubic <http:\/\/en.wikipedia.org\/wiki\/B%C3%A9zier_surface B\u00c3\u00a9zier patch>.\r\n% This is the patch that we saw in <https:\/\/blogs.mathworks.com\/graphics\/2014\/10\/03\/welcome\/ my first blog post here>\r\n% when we were looking at Newell's teapot. You'll also notice the\r\n% similarities to the equation for the cubic B\u00c3\u00a9zier curve we saw in \r\n% <https:\/\/blogs.mathworks.com\/graphics\/2014\/10\/13\/bezier-curves\/ my second\r\n% post>.\r\nMbezier = [-1  3 -3 1; ...\r\n            3 -6  3 0; ...\r\n           -3  3  0 0; ...\r\n            1  0  0 0];\r\n        \r\n%%\r\n%\r\n% We can use that to generate a surface with one set of isoparameter lines like this:\r\nM = Mbezier;\r\n\r\n% U & V vectors  \r\nu = linspace(0,1,50);\r\nv = linspace(0,1,50)';\r\nu_powers = [u.^3; u.^2; u; ones(size(u))];\r\nv_powers = [v.^3, v.^2, v, ones(size(v))];\r\n\r\n% Multiply to get X,Y, & Z \r\nxout = v_powers * M * px * M' * u_powers;\r\nyout = v_powers * M * py * M' * u_powers;\r\nzout = v_powers * M * pz * M' * u_powers;\r\n\r\n% Draw as a surface\r\nhold on\r\ns = surf(xout,yout,zout);\r\ns.FaceColor = 'none';\r\ns.MeshStyle = 'row';\r\n\r\n%%\r\n% And then the show the other set of isoparameter lines like this:\r\ns.MeshStyle = 'column';\r\n\r\n%%\r\n% or as a shaded surface with lighting.\r\ns.EdgeColor = 'none';\r\ns.FaceColor = 'interp';\r\ns.FaceLighting = 'gouraud';\r\ns.SpecularStrength = 5\/8;\r\nlight('Position',[9 -5 8])\r\n\r\n%%\r\n% A coarser colormap will add \"waterlevel\" lines.\r\ncolormap(lines(20))\r\n\r\n%%\r\n% Notice that the B\u00c3\u00a9zier patch has the same characteristics we saw in the\r\n% earlier blog post about the curves. It passes through the 4 control points \r\n% in the corners of the 4x4 set, it's tangent to the control point mesh at \r\n% those corners, and it's completely contained within the bounds of the \r\n% control point mesh. These are really useful properties and they make \r\n% B\u00c3\u00a9zier very easy to work with.\r\n\r\n%%\r\n% The \"Patch Work\" memo includes the basis matrices for a number of other\r\n% types of patches, but some of them are a little trickier to work with. \r\n%\r\n% Let's try the <http:\/\/en.wikipedia.org\/wiki\/Centripetal_Catmull%E2%80%93Rom_spline\r\n% Catmull-Rom> patch.\r\nMcatmullrom = [-1  3 -3  1; ...\r\n                2 -5  4 -1; ...\r\n               -1  0  1  0; ...\r\n                0  2  0  0] \/ 2;\r\nM = Mcatmullrom;\r\ns.XData = v_powers * M * px * M' * u_powers;\r\ns.YData = v_powers * M * py * M' * u_powers;\r\ns.ZData = v_powers * M * pz * M' * u_powers;\r\n\r\n%%\r\n% It's a little hard to see from that viewing angle, but the way a\r\n% Catmull-Rom spline works is that it connects the inner 2x2 points of our\r\n% control point mesh.\r\nview(-37.5,60)\r\n\r\n%%\r\n% The other points in the control mesh of a Catmull-Rom patch simply\r\n% control the tangents at the edges of the patch. The way you usually use\r\n% these is to have two rows of control points be shared between neighboring\r\n% patches. This ensures that the patches have a nice, smooth blend where\r\n% they meet. It is possible to get the same effect with B\u00c3\u00a9zier patches, but\r\n% it is a little bit trickier.\r\n\r\n%%\r\n% The basis matrix for the B-spline patch looks like this.\r\nMbspline = [-1  3 -3 1; ...\r\n             3 -6  3 0; ...\r\n            -3  0  3 0; ...\r\n             1  4  1 0] \/ 6;\r\nM = Mbspline;\r\ns.XData = v_powers * M * px * M' * u_powers;\r\ns.YData = v_powers * M * py * M' * u_powers;\r\ns.ZData = v_powers * M * pz * M' * u_powers;\r\nview(3)\r\n\r\n%%\r\n% You can see that this patch also only covers the inner 2x2 of our control\r\n% point mesh, and it doesn't even pass through those points. This property\r\n% makes the B-spline patch kind of challenging to work with when you're\r\n% trying to model something.\r\n%\r\n% But the \"patch work\" memo also shows how to convert the control points of\r\n% one kind of patch to those of another kind of patch. To do this, we need\r\n% what it calls \"to-from\" matrices. We can use this to convert our friendly\r\n% B\u00c3\u00a9zier patch control points into ones which work for the B-spline patch\r\n% by using this matrix.\r\nMtofrom = [6 -7  2 0; ...\r\n           0  2 -1 0; ...\r\n           0 -1  2 0; ...\r\n           0  2 -7 6];\r\n\r\npxnew = Mtofrom * px * Mtofrom';\r\npynew = Mtofrom * py * Mtofrom';\r\npznew = Mtofrom * pz * Mtofrom';\r\n       \r\n%%\r\n% If we compare the control points before and after this transformation, we\r\n% can see that the ones for the B-spline patch extand way outside the ones for\r\n% the B\u00c3\u00a9zier patch, and the Z range is much wider.\r\nf2 = figure;\r\np1 = stem3(px,py,pz,'filled');\r\nhold on\r\np2 = stem3(pxnew,pynew,pznew,'filled');\r\nsurf(pxnew,pynew,pznew,'FaceColor','none','EdgeColor',[.85 .85 .85])\r\nxlim([-inf inf])\r\nylim([-inf inf])\r\n\r\n%%\r\n% But when we use these new points with the basis matrix for the B-spline patch,\r\n% they will give us the same surface we got with the B\u00c3\u00a9zier patch using the \r\n% original control points.\r\ndelete(f2)\r\ns.XData = v_powers * M * pxnew * M' * u_powers;\r\ns.YData = v_powers * M * pynew * M' * u_powers;\r\ns.ZData = v_powers * M * pznew * M' * u_powers;\r\n\r\n%%\r\n% Being able to convert between different patch types is extremely useful\r\n% because the different types have different properties which are useful in\r\n% different situations.\r\n%\r\n% You can find all of the to-from matrices in\r\n% <https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/patch_work_details.m \r\n% this file>.\r\n%\r\n% But there are more goodies hiding in this memo. We saw when we talked\r\n% about <https:\/\/blogs.mathworks.com\/graphics\/2014\/12\/04\/tie-a-ribbon-round-it-parametric-curves-part-1\/\r\n% parametric curves> that being able to compute partial derivatives of\r\n% the curves is very useful for creating tangents and normals. The same is\r\n% true when you're working with surface patches, and this memo has a\r\n% section on how to compute partial derivatives of the patches. To compute\r\n% those, we need the following two matrices.\r\ndu = [0 3 0 0; ...\r\n      0 0 2 0; ...\r\n      0 0 0 1; ...\r\n      0 0 0 0];\r\n  \r\ndv = [0 0 0 0; ...\r\n      3 0 0 0; ...\r\n      0 2 0 0; ...\r\n      0 0 1 0];\r\n\r\n%%\r\n% We'll create a low-res parameterization.\r\nM = Mbezier;\r\nu = linspace(0,1,10);\r\nv = linspace(0,1,10)';\r\nu_powers = [u.^3; u.^2; u; ones(size(u))];\r\nv_powers = [v.^3, v.^2, v, ones(size(v))];\r\n\r\nxout = v_powers * M * px * M' * u_powers;\r\nyout = v_powers * M * py * M' * u_powers;\r\nzout = v_powers * M * pz * M' * u_powers;\r\n\r\n%%\r\n% And then we use the matrices du and dv like this:\r\ndxdu = v_powers * M * px * M' * du * u_powers;\r\ndydu = v_powers * M * py * M' * du * u_powers;\r\ndzdu = v_powers * M * pz * M' * du * u_powers;\r\ndxdv = v_powers * dv * M * px * M' * u_powers;\r\ndydv = v_powers * dv * M * py * M' * u_powers;\r\ndzdv = v_powers * dv * M * pz * M' * u_powers;\r\n\r\n\r\n%%\r\n% We could use the cross product of those two vectors to compute normals\r\n% which are much smoother than what the surface command can create. Or we \r\n% can use them directly to cover the surface with a bunch of tangent circles \r\n% like this:\r\nxlim manual\r\nylim manual\r\nzlim manual\r\ndelete(s)\r\nradius = .05;\r\ntheta = linspace(0,2*pi,72); % points around the circles\r\nfor i=1:numel(xout)\r\n    % c + r*(cos(theta)*dp\/du + sin(theta)*dp\/dv)\r\n    cx = xout(i) + radius*(cos(theta)*dxdu(i) + sin(theta)*dxdv(i));\r\n    cy = yout(i) + radius*(cos(theta)*dydu(i) + sin(theta)*dydv(i));\r\n    cz = zout(i) + radius*(cos(theta)*dzdu(i) + sin(theta)*dzdv(i));\r\n    h = patch(cx,cy,cz,zeros(size(cx)));\r\n    h.FaceColor = [.875 .875 .875];\r\n    h.EdgeColor = 'none';\r\nend\r\n\r\n%%\r\n% Can you combine this with what we did in the\r\n% <https:\/\/blogs.mathworks.com\/graphics\/2014\/10\/03\/welcome\/ teapot blog\r\n% post> to create a picture that looks like this?\r\n%\r\n% <<..\/disk_teapot.png>>\r\n%\r\n\r\n##### SOURCE END ##### 4f1e2b9a0e794e95b0ca7bd46684dee5\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/graphics\/files\/feature_image\/patch_work_thumbnail.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>Patch WorkBack before the internet, programmers collected xeroxed copies of old notes and papers. We traded these with our friends and coworkers, like samizdat. I still have a large filing cabinet... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/05\/12\/patch-work\/\">read more >><\/a><\/p>","protected":false},"author":89,"featured_media":240,"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\/239"}],"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=239"}],"version-history":[{"count":6,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/239\/revisions"}],"predecessor-version":[{"id":246,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/239\/revisions\/246"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media\/240"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media?parent=239"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/categories?post=239"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/tags?post=239"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}