{"id":274,"date":"2015-07-22T10:08:24","date_gmt":"2015-07-22T14:08:24","guid":{"rendered":"https:\/\/blogs.mathworks.com\/graphics\/?p=274"},"modified":"2015-07-22T10:08:24","modified_gmt":"2015-07-22T14:08:24","slug":"implicit-surface-intersections","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/graphics\/2015\/07\/22\/implicit-surface-intersections\/","title":{"rendered":"Implicit Surface Intersections"},"content":{"rendered":"<div class=\"content\"><h3>Implicit Surface Intersections<\/h3><p>We talked about implicit surfaces here <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/03\/03\/implicit-curves\/\">back in March<\/a>. Recently, there was an interesting <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/answers\/229743-how-can-i-find-intersection-of-a-cylinder-and-helical-isosurface\">question about them<\/a> on MATLAB Answers.<\/p><p>Dr. Vyas has a surface which is defined by the following equation.<\/p><p>$$y - x*tan(z) = 0$$<\/p><p>It apparently comes from a problem involving polarization of light by crystals.<\/p><p>He has already figured out how to compute the surface ...<\/p><pre class=\"codeinput\">[x3, y3,z3] = meshgrid(linspace(-1.25, 1.25, 150), <span class=\"keyword\">...<\/span>\r\n                       linspace(-1.25, 1.25, 150), <span class=\"keyword\">...<\/span>\r\n                       linspace(0, 2*pi, 150));\r\nf2 = y3-x3.*tan(z3);\r\nhel = isosurface(x3, y3, z3, f2, 0);\r\n<\/pre><p>... and draw it using the technique we talked about in that blog post.<\/p><pre class=\"codeinput\">patch(hel,<span class=\"string\">'FaceColor'<\/span>,[1 .5 0],<span class=\"string\">'EdgeColor'<\/span>,<span class=\"string\">'none'<\/span>);\r\nview(3)\r\ncamlight\r\nax = gca;\r\nset(ax,<span class=\"string\">'XLim'<\/span>,[-inf inf],<span class=\"string\">'YLim'<\/span>,[-inf inf],<span class=\"string\">'ZLim'<\/span>,[-inf inf],<span class=\"string\">'DataAspectRatio'<\/span>,[1 1 1])\r\nbox <span class=\"string\">on<\/span>\r\nxlabel(<span class=\"string\">'x(mm)'<\/span>)\r\nylabel(<span class=\"string\">'y(mm)'<\/span>)\r\nzlabel(<span class=\"string\">'\\Lambda[rad]'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/implicit_surface_intersections_01.png\" alt=\"\"> <p>But now he wants to compute the interesection of that surface and the cylinder defined by this equation:<\/p><p>$$x^2 + y^2 = 1$$<\/p><p>In general, computing the interestion of implicit surfaces is a fairly challenging problem. There are three basic approaches.<\/p><div><ol><li>Find an analytic solution for the intersection.<\/li><li>Find an intersection point, and then use a tracing scheme to generate the curve.<\/li><li>Calculate the intersection on the grid we're using to draw the surfaces.<\/li><\/ol><\/div><p>The first two approaches can be fairly involved in some cases, but the third approach generally isn't too hard to implement. Let's walk through that approach in detail.<\/p><p>First we take the vertices we got from the isosurface, and create a logical mask of all of the vertices which are outside the cylinder. To do that, we just need to compute the radius for each vertex, and then compare that to 1.<\/p><pre class=\"codeinput\">r = sqrt(hel.vertices(:,1).^2 + hel.vertices(:,2).^2);\r\ncylrad = 1;\r\nmask = r&gt;cylrad;\r\n<\/pre><p>For each triangle, count the number of vertices which are outside the cylinder.<\/p><pre class=\"codeinput\">outcount = sum(mask(hel.faces),2);\r\n<\/pre><p>If the number of outside vertices is 0 or 3, then we don't care about the triangle. That's because those triangles are completely inside or completely outside the cylinder. This means that they can't contribute to the intersection curve.<\/p><p>If the number of outside vertices is 1 or 2, then the triangle crosses the cylinder. These are the triangles we're interested in.<\/p><pre class=\"codeinput\">cross = (outcount == 2) | (outcount == 1);\r\ncrossing_tris = hel.faces(cross,:);\r\n<\/pre><p>Let's take a quicky look at those triangles.<\/p><pre class=\"codeinput\">cla\r\nct = patch(<span class=\"string\">'Vertices'<\/span>,hel.vertices,<span class=\"string\">'Faces'<\/span>,crossing_tris,<span class=\"string\">'EdgeColor'<\/span>,[1 .5 0],<span class=\"string\">'FaceColor'<\/span>,[.5 1 .5]);\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/implicit_surface_intersections_02.png\" alt=\"\"> <p>That looks pretty close. If we zoom in we can see that we have a thin band of triangles which go around the part of the surface which crosses the cylinder.<\/p><pre class=\"codeinput\">xlim([-.375 .375])\r\nylim([-1 -.75])\r\nzlim([1.3 1.8])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/implicit_surface_intersections_03.png\" alt=\"\"> <p>Now we need to take each of those triangles and turn it into a line segment which shows the intersection.<\/p><p>The math for calculating the intersection actually involves terms which cancel out so that the calculation for the 1-out and 2-out triangles look the same. So at this point we'll simplify things by flipping all of the 1-out triangles around so that they look like 2-out triangles. That way we only have to deal with one type of triangle.<\/p><pre class=\"codeinput\">out_vert = mask(crossing_tris);\r\nflip = sum(out_vert,2) == 1;\r\nout_vert(flip,:) = 1-out_vert(flip,:);\r\n<\/pre><p>Here's where things get a little messy. Each row of out_vert contains one 0 and two 1's. We want to draw a line between the edges of the triangles which connect the vertex with the 0 with each of the two vertices with a 1.<\/p><p>I'm sure there's a cleaner way to do this, but here's what I came up with.<\/p><pre class=\"codeinput\">ntri = size(out_vert,1);\r\novert = zeros(ntri,3);\r\n<span class=\"keyword\">for<\/span> i=1:ntri\r\n    v1i = find(~out_vert(i,:));\r\n    v2i = 1 + mod(v1i,3);\r\n    v3i = 1 + mod(v1i+1,3);\r\n    overt(i,:) = crossing_tris(i,[v1i v2i v3i]);\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><p>It's all downhill from there!<\/p><p>Next we need to calculate where each of those two edges of the triangle cross the cylinder.<\/p><p>We've already computed the radius at each vertex, so we can compute u &amp; v parameters for linear interpolation like this:<\/p><pre class=\"codeinput\">u = (cylrad - r(overt(:,1))) .\/ (r(overt(:,2)) - r(overt(:,1)));\r\nv = (cylrad - r(overt(:,1))) .\/ (r(overt(:,3)) - r(overt(:,1)));\r\n<\/pre><p>And then use those to do the linear interpolation to compute the position where the edge crosses the cylinder like this:<\/p><pre class=\"codeinput\">uverts = repmat((1-u),[1 3]).*hel.vertices(overt(:,1),:) + repmat(u,[1 3]).*hel.vertices(overt(:,2),:);\r\nvverts = repmat((1-v),[1 3]).*hel.vertices(overt(:,1),:) + repmat(v,[1 3]).*hel.vertices(overt(:,3),:);\r\n<\/pre><p>Next we use the 3-row with nan trick I described <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/06\/09\/object-creation-performance\/\">in this post<\/a> to convert those pairs of vertices into one line object.<\/p><pre class=\"codeinput\">x = nan(3,ntri);\r\nx(1,:) = uverts(:,1)';\r\nx(2,:) = vverts(:,1)';\r\ny = nan(3,ntri);\r\ny(1,:) = uverts(:,2)';\r\ny(2,:) = vverts(:,2)';\r\nz = nan(3,ntri);\r\nz(1,:) = uverts(:,3)';\r\nz(2,:) = vverts(:,3)';\r\n<\/pre><p>OK, now we'll draw the resulting lines on top of the triangles we had earlier.<\/p><pre class=\"codeinput\">h = line(x(:),y(:),z(:));\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/implicit_surface_intersections_04.png\" alt=\"\"> <p>And then zoom back out.<\/p><pre class=\"codeinput\">delete(ct)\r\nset(ax,<span class=\"string\">'XLim'<\/span>,[-inf inf],<span class=\"string\">'YLim'<\/span>,[-inf inf],<span class=\"string\">'ZLim'<\/span>,[-inf inf],<span class=\"string\">'DataAspectRatio'<\/span>,[1 1 1])\r\nh.Color = ax.ColorOrder(5,:);\r\nh.LineWidth = 2;\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/implicit_surface_intersections_05.png\" alt=\"\"> <p>Next we can add the helical surface back in, and turn it so we can see things a little more clearly.<\/p><pre class=\"codeinput\">p = patch(<span class=\"string\">'Vertices'<\/span>,hel.vertices,<span class=\"string\">'Faces'<\/span>,hel.faces,<span class=\"string\">'EdgeColor'<\/span>,<span class=\"string\">'none'<\/span>);\r\np.FaceColor = ax.ColorOrder(2,:);\r\nlight(<span class=\"string\">'Position'<\/span>,[-7 -8 90])\r\nlight(<span class=\"string\">'Position'<\/span>,[-1 1 .25])\r\nset(p,<span class=\"string\">'SpecularStrength'<\/span>,.6,<span class=\"string\">'DiffuseStrength'<\/span>,.85,<span class=\"string\">'AmbientStrength'<\/span>,.15,<span class=\"string\">'BackFaceLighting'<\/span>,<span class=\"string\">'reverselit'<\/span>)\r\nset(ax,<span class=\"string\">'CameraPosition'<\/span>,[-4 7 15],<span class=\"string\">'CameraUpVector'<\/span>,[-1 0 0])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/implicit_surface_intersections_06.png\" alt=\"\"> <p>And we can add the cylinder like this:<\/p><pre class=\"codeinput\">f1 = x3.^2+y3.^2-1;\r\ncyl = patch(isosurface(x3, y3, z3, f1, 0),<span class=\"string\">'EdgeColor'<\/span>, <span class=\"string\">'none'<\/span>);\r\ncyl.FaceColor = ax.ColorOrder(1,:);\r\nset(cyl,<span class=\"string\">'SpecularStrength'<\/span>,.6,<span class=\"string\">'DiffuseStrength'<\/span>,.85,<span class=\"string\">'AmbientStrength'<\/span>,.15,<span class=\"string\">'BackFaceLighting'<\/span>,<span class=\"string\">'reverselit'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/implicit_surface_intersections_07.png\" alt=\"\"> <p>Finally, let's look at it with just the cylinder and the intersection curve.<\/p><pre class=\"codeinput\">xlim([-1.25 1.25])\r\nylim([-1.25 1.25])\r\np.Visible = <span class=\"string\">'off'<\/span>;\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/implicit_surface_intersections_08.png\" alt=\"\"> <p>If you're working with implicit surfaces, you'll probably find that this is a useful technique to have in your toolbox. You can also modify it to do a number of other interesting things. For example, if I had just kept the triangles with a outcount of 0, I would have gotten just the portion of the surface which lies on the inside of the cylinder.<\/p><pre class=\"codeinput\">cla\r\nax = gca;\r\ncrossing_tris = hel.faces(outcount==0,:);\r\np = patch(<span class=\"string\">'Vertices'<\/span>,hel.vertices,<span class=\"string\">'Faces'<\/span>,crossing_tris,<span class=\"string\">'FaceColor'<\/span>,ax.ColorOrder(2,:),<span class=\"string\">'EdgeColor'<\/span>,<span class=\"string\">'none'<\/span>);\r\nview(3)\r\nset(ax,<span class=\"string\">'XLim'<\/span>,[-inf inf],<span class=\"string\">'YLim'<\/span>,[-inf inf],<span class=\"string\">'ZLim'<\/span>,[-inf inf],<span class=\"string\">'DataAspectRatio'<\/span>,[1 1 1])\r\nbox <span class=\"string\">on<\/span>\r\nlight(<span class=\"string\">'Position'<\/span>,[-7 -8 90])\r\nlight(<span class=\"string\">'Position'<\/span>,[-1 1 .25])\r\nset(p,<span class=\"string\">'SpecularStrength'<\/span>,.6,<span class=\"string\">'DiffuseStrength'<\/span>,.85,<span class=\"string\">'AmbientStrength'<\/span>,.15,<span class=\"string\">'BackFaceLighting'<\/span>,<span class=\"string\">'reverselit'<\/span>)\r\nset(ax,<span class=\"string\">'CameraPosition'<\/span>,[-4 7 15],<span class=\"string\">'CameraUpVector'<\/span>,[-1 0 0])\r\nxlabel(<span class=\"string\">'x(mm)'<\/span>)\r\nylabel(<span class=\"string\">'y(mm)'<\/span>)\r\nzlabel(<span class=\"string\">'\\Lambda[rad]'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/implicit_surface_intersections_09.png\" alt=\"\"> <p>To do a really nice job of this, we would need to trim the triangles which cross the cylinder. The math for that would be similar to what we did to generate those lines.<\/p><p>We could extend this even further and trim each of the surfaces against the other. Then we'd get the region bounded by those surfaces without any extraneous bits.<\/p><p>Can you think of other things you could do with this technique? Do you have some interesting implicit surfaces you could use this on? I'd love to see what you can create with it.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_97308affa85149c09f68c1c1176c14c7() {\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='97308affa85149c09f68c1c1176c14c7 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 97308affa85149c09f68c1c1176c14c7';\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_97308affa85149c09f68c1c1176c14c7()\"><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\n97308affa85149c09f68c1c1176c14c7 ##### SOURCE BEGIN #####\r\n%% Implicit Surface Intersections\r\n%\r\n% We talked about implicit surfaces here\r\n% <https:\/\/blogs.mathworks.com\/graphics\/2015\/03\/03\/implicit-curves\/ back in\r\n% March>.\r\n% Recently, there was an interesting\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/answers\/229743-how-can-i-find-intersection-of-a-cylinder-and-helical-isosurface\r\n% question about them> on MATLAB Answers. \r\n%\r\n% Dr. Vyas has a surface which is defined by the following equation.\r\n%\r\n% $$y - x*tan(z) = 0$$\r\n%\r\n% It apparently comes from a problem involving polarization of light by\r\n% crystals.\r\n%\r\n% He has already figured out how to compute the surface ...\r\n%\r\n[x3, y3,z3] = meshgrid(linspace(-1.25, 1.25, 150), ...\r\n                       linspace(-1.25, 1.25, 150), ...\r\n                       linspace(0, 2*pi, 150)); \r\nf2 = y3-x3.*tan(z3); \r\nhel = isosurface(x3, y3, z3, f2, 0);\r\n\r\n%%\r\n% ... and draw it using the technique we talked about in that blog post.\r\n%\r\npatch(hel,'FaceColor',[1 .5 0],'EdgeColor','none');\r\nview(3)\r\ncamlight\r\nax = gca;\r\nset(ax,'XLim',[-inf inf],'YLim',[-inf inf],'ZLim',[-inf inf],'DataAspectRatio',[1 1 1])\r\nbox on\r\nxlabel('x(mm)')\r\nylabel('y(mm)')\r\nzlabel('\\Lambda[rad]')\r\n\r\n%%\r\n% But now he wants to compute the interesection of that surface and the\r\n% cylinder defined by this equation:\r\n%\r\n% $$x^2 + y^2 = 1$$\r\n%\r\n% In general, computing the interestion of implicit surfaces is a fairly\r\n% challenging problem. There are three basic approaches.\r\n%\r\n% # Find an analytic solution for the intersection.\r\n% # Find an intersection point, and then use a tracing scheme to generate\r\n% the curve.\r\n% # Calculate the intersection on the grid we're using to draw the\r\n% surfaces.\r\n%\r\n% The first two approaches can be fairly involved in some cases, but the \r\n% third approach generally isn't too hard to implement. Let's walk through \r\n% that approach in detail. \r\n%\r\n% First we take the vertices we got from the isosurface, and create a logical \r\n% mask of all of the vertices which are outside the cylinder. To do that,\r\n% we just need to compute the radius for each vertex, and then compare that to 1.\r\n%\r\nr = sqrt(hel.vertices(:,1).^2 + hel.vertices(:,2).^2);\r\ncylrad = 1;\r\nmask = r>cylrad;\r\n\r\n%%\r\n% For each triangle, count the number of vertices which are outside the\r\n% cylinder.\r\noutcount = sum(mask(hel.faces),2);\r\n\r\n%%\r\n% If the number of outside vertices is 0 or 3, then we don't care about the\r\n% triangle. That's because those triangles are completely inside or\r\n% completely outside the cylinder. This means that they can't contribute to\r\n% the intersection curve.\r\n%\r\n% If the number of outside vertices is 1 or 2, then the triangle crosses the cylinder.\r\n% These are the triangles we're interested in.\r\n%\r\ncross = (outcount == 2) | (outcount == 1);\r\ncrossing_tris = hel.faces(cross,:);\r\n\r\n%%\r\n% Let's take a quicky look at those triangles.\r\ncla\r\nct = patch('Vertices',hel.vertices,'Faces',crossing_tris,'EdgeColor',[1 .5 0],'FaceColor',[.5 1 .5]);\r\n\r\n%%\r\n% That looks pretty close. If we zoom in we can see that we have a thin\r\n% band of triangles which go around the part of the surface which crosses\r\n% the cylinder.\r\nxlim([-.375 .375])\r\nylim([-1 -.75])\r\nzlim([1.3 1.8])\r\n\r\n%%\r\n% Now we need to take each of those triangles and turn it into a line\r\n% segment which shows the intersection.\r\n%\r\n% The math for calculating the intersection actually involves terms\r\n% which cancel out so that the calculation for the 1-out and 2-out triangles look the same. So at\r\n% this point we'll simplify things by flipping all of the 1-out triangles\r\n% around so that they look like 2-out triangles. That way we only have to \r\n% deal with one type of triangle.\r\n%\r\nout_vert = mask(crossing_tris);\r\nflip = sum(out_vert,2) == 1;\r\nout_vert(flip,:) = 1-out_vert(flip,:);\r\n\r\n%%\r\n% Here's where things get a little messy. Each row of out_vert contains one\r\n% 0 and two 1's. We want to draw a line between the edges of the triangles\r\n% which connect the vertex with the 0 with each of the two vertices with a 1.\r\n%\r\n% I'm sure there's a cleaner way to do this, but here's what I came up\r\n% with.\r\n%\r\nntri = size(out_vert,1);\r\novert = zeros(ntri,3);\r\nfor i=1:ntri\r\n    v1i = find(~out_vert(i,:));\r\n    v2i = 1 + mod(v1i,3);\r\n    v3i = 1 + mod(v1i+1,3);\r\n    overt(i,:) = crossing_tris(i,[v1i v2i v3i]);\r\nend\r\n\r\n%%\r\n% It's all downhill from there! \r\n%\r\n% Next we need to calculate where each of those two edges of the triangle \r\n% cross the cylinder.\r\n%\r\n% We've already computed the radius at each vertex, so we can compute u & v\r\n% parameters for linear interpolation like this:\r\n%\r\nu = (cylrad - r(overt(:,1))) .\/ (r(overt(:,2)) - r(overt(:,1)));\r\nv = (cylrad - r(overt(:,1))) .\/ (r(overt(:,3)) - r(overt(:,1)));\r\n\r\n%%\r\n% And then use those to do the linear interpolation to compute the position \r\n% where the edge crosses the cylinder like this:\r\n%\r\nuverts = repmat((1-u),[1 3]).*hel.vertices(overt(:,1),:) + repmat(u,[1 3]).*hel.vertices(overt(:,2),:);\r\nvverts = repmat((1-v),[1 3]).*hel.vertices(overt(:,1),:) + repmat(v,[1 3]).*hel.vertices(overt(:,3),:);\r\n\r\n%%\r\n% Next we use the 3-row with nan trick I described\r\n% <https:\/\/blogs.mathworks.com\/graphics\/2015\/06\/09\/object-creation-performance\/ \r\n% in this post> to convert those pairs of vertices into one line object.\r\n%\r\nx = nan(3,ntri);\r\nx(1,:) = uverts(:,1)';\r\nx(2,:) = vverts(:,1)';\r\ny = nan(3,ntri);\r\ny(1,:) = uverts(:,2)';\r\ny(2,:) = vverts(:,2)';\r\nz = nan(3,ntri);\r\nz(1,:) = uverts(:,3)';\r\nz(2,:) = vverts(:,3)';\r\n\r\n%%\r\n% OK, now we'll draw the resulting lines on top of the triangles we had\r\n% earlier.\r\nh = line(x(:),y(:),z(:));\r\n\r\n%%\r\n% And then zoom back out.\r\ndelete(ct)\r\nset(ax,'XLim',[-inf inf],'YLim',[-inf inf],'ZLim',[-inf inf],'DataAspectRatio',[1 1 1])\r\nh.Color = ax.ColorOrder(5,:);\r\nh.LineWidth = 2;\r\n\r\n%%\r\n% Next we can add the helical surface back in, and turn it so we can see\r\n% things a little more clearly.\r\n%\r\np = patch('Vertices',hel.vertices,'Faces',hel.faces,'EdgeColor','none');\r\np.FaceColor = ax.ColorOrder(2,:);\r\nlight('Position',[-7 -8 90])\r\nlight('Position',[-1 1 .25])\r\nset(p,'SpecularStrength',.6,'DiffuseStrength',.85,'AmbientStrength',.15,'BackFaceLighting','reverselit')\r\nset(ax,'CameraPosition',[-4 7 15],'CameraUpVector',[-1 0 0])\r\n\r\n%%\r\n% And we can add the cylinder like this:\r\n%\r\nf1 = x3.^2+y3.^2-1; \r\ncyl = patch(isosurface(x3, y3, z3, f1, 0),'EdgeColor', 'none');\r\ncyl.FaceColor = ax.ColorOrder(1,:);\r\nset(cyl,'SpecularStrength',.6,'DiffuseStrength',.85,'AmbientStrength',.15,'BackFaceLighting','reverselit')\r\n\r\n%%\r\n% Finally, let's look at it with just the cylinder and the intersection\r\n% curve.\r\nxlim([-1.25 1.25])\r\nylim([-1.25 1.25])\r\np.Visible = 'off';\r\n\r\n%%\r\n% If you're working with implicit surfaces, you'll probably find that this\r\n% is a useful technique to have in your toolbox. You can also modify it to\r\n% do a number of other interesting things. For example, if I had just kept\r\n% the triangles with a outcount of 0, I would have gotten just the portion of\r\n% the surface which lies on the inside of the cylinder.\r\n%\r\ncla\r\nax = gca;\r\ncrossing_tris = hel.faces(outcount==0,:);\r\np = patch('Vertices',hel.vertices,'Faces',crossing_tris,'FaceColor',ax.ColorOrder(2,:),'EdgeColor','none');\r\nview(3)\r\nset(ax,'XLim',[-inf inf],'YLim',[-inf inf],'ZLim',[-inf inf],'DataAspectRatio',[1 1 1])\r\nbox on\r\nlight('Position',[-7 -8 90])\r\nlight('Position',[-1 1 .25])\r\nset(p,'SpecularStrength',.6,'DiffuseStrength',.85,'AmbientStrength',.15,'BackFaceLighting','reverselit')\r\nset(ax,'CameraPosition',[-4 7 15],'CameraUpVector',[-1 0 0])\r\nxlabel('x(mm)')\r\nylabel('y(mm)')\r\nzlabel('\\Lambda[rad]')\r\n\r\n%%\r\n% To do a really nice job of this, we would need to trim the triangles which cross the\r\n% cylinder. The math for that would be similar to what we did to generate\r\n% those lines.\r\n%\r\n% We could extend this even further and trim each of the surfaces against\r\n% the other. Then we'd get the region bounded by those surfaces without any\r\n% extraneous bits.\r\n%\r\n% Can you think of other things you could do with this technique? Do you\r\n% have some interesting implicit surfaces you could use this on? I'd love\r\n% to see what you can create with it.\r\n%\r\n\r\n##### SOURCE END ##### 97308affa85149c09f68c1c1176c14c7\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/graphics\/files\/feature_image\/implicit_intersection_thumbnail.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>Implicit Surface IntersectionsWe talked about implicit surfaces here back in March. Recently, there was an interesting question about them on MATLAB Answers.Dr. Vyas has a surface which is defined by... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/07\/22\/implicit-surface-intersections\/\">read more >><\/a><\/p>","protected":false},"author":89,"featured_media":276,"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\/274"}],"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=274"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/274\/revisions"}],"predecessor-version":[{"id":275,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/274\/revisions\/275"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media\/276"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media?parent=274"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/categories?post=274"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/tags?post=274"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}