{"id":998,"date":"2021-08-25T19:44:48","date_gmt":"2021-08-25T19:44:48","guid":{"rendered":"http:\/\/summergeometry.org\/sgi2021\/?p=998"},"modified":"2021-08-25T19:44:49","modified_gmt":"2021-08-25T19:44:49","slug":"intrinsic-parameterization-weeks-1-2","status":"publish","type":"post","link":"https:\/\/summergeometry.org\/sgi2021\/intrinsic-parameterization-weeks-1-2\/","title":{"rendered":"Intrinsic Parameterization: Weeks 1-2"},"content":{"rendered":"\n<p class=\"has-text-align-center wp-block-paragraph\"><em>By Joana Portmann, Tal Rastopchin, and Sahra Yusuf.<\/em><br><em>Mentored by Professor Keenan Crane.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Intrinsic  parameterization<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">During these last two weeks, we explored intrinsic encoding of triangle meshes. As an introduction to this new topic, we wrote a very simple algorithm that lays out a triangle mesh flat. We then improved this algorithm via line search over a week. In connection with this, we looked into terms like &#8216;angle defects,&#8217; &#8216;cotangent weights,&#8217; and the &#8216;cotangent Laplacian&#8217; in preparation for more current research during the week.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">From intrinsic to extrinsic parameterization<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">To get a short introduction into intrinsic parameterization and its applications, I quote some sentences from Keenan\u2019s course. If you\u2019re interested in the subject I can recommend the course notes &#8220;<a rel=\"noreferrer noopener\" href=\"https:\/\/nmwsharp.com\/media\/papers\/int-tri-course\/int_tri_course.pdf\" data-type=\"URL\" data-id=\"https:\/\/nmwsharp.com\/media\/papers\/int-tri-course\/int_tri_course.pdf\" target=\"_blank\">Geometry Processing with Intrinsic Triangulations<\/a>.&#8221; &#8220;As triangle meshes are a basic representation for 3D geometry, playing the same central role as pixel arrays in image processing, even seemingly small shifts in the way we think about triangle meshes can have major consequences for a wide variety of applications. Instead of thinking about a triangle as a collection of vertex positions in \\(\\mathbb{R}^n\\) from the intrinsic perspective, it&#8217;s a collection of edge lengths associated with edges.&#8221;&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Many properties of a surface such as the shortest path do only depend on local measurements such as angles and distances along the surfaces and do not depend on how the surface is embedded in space (e.g. vertex positions in \\(\\mathbb{R}^n\\)), so an intrinsic representation of the mesh works fine. Intrinsic triangulations bring several deep ideas from topology and differential geometry into a discrete, computational setting. And the framework of intrinsic triangulations is particularly useful for improving the robustness of existing algorithms.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Laying out edge lengths in the plane<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Our first task was to implement a simple algorithm that uses intrinsic edge lengths and a breadth-first search to flatten a triangle mesh onto the plane. The key idea driving this algorithm is that given just a triangle\u2019s edge lengths we can use the law of cosines to compute its internal angles. Given a triangle in the plane we can use the internal angles to flatten out its neighbors into the plane. We will later use these angles to modify the edge lengths so that we &#8220;better&#8221; flatten the model. The algorithm works by choosing some root triangle and then performing a breadth-first traversal to flatten each of the adjacent triangles into the plane until we have visited every triangle in the mesh.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Breadth-first search pseudocode<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Some initial geometry central pseudocode for this breadth first search looks something like<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n\/\/ Pick and flatten some starting triangle\nFace rootTriangle = mesh-&gt;face(0);\n\n\/\/ Calculate the root triangle\u2019s flattened vertex positions\ncalculateFlatVertices(rootTriangle);\n\n\/\/ Initialize a map encoding visited faces\nFaceData&lt;bool&gt; isVisited(*mesh, false);\n\n\/\/ Initialize a queue for the BFS\nstd::queue&lt;Face&gt; visited;\n\n\/\/ Mark the root triangle as visited and pop it into the queue\nisVisited&#091;rootTriangle] = true;\nvisited.push(rootTriangle);\n\n\/\/ While our queue is not empty\nwhile(!visited.empty())\n{\n    \/\/ Pop the current Face off the front of the queue\n    Face currentFace = visited.front();\n    visited.pop();\n\n    \/\/ Visit the adjacent faces\n    For (Face adjFace : currentFace.adjacentFaces()) {\n        \/\/ If we have not already visited the face\n        if (!visited&#091;adjFace]\n            \/\/ Calculate the triangle\u2019s flattened vertex positions\n            calculateFlatVertices(adjFace);\n            \/\/ And push it onto the queue\n            visited.push(adjFace);\n        }\n    }\n}\n\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">In order to make sure we lay down adjacent triangles with respect to the computed flattened plane coordinates of their parent triangle we need to know exactly how a child triangle connects to its parent triangle. Specifically, we need to know which edge is shared by the parent and child triangle and&nbsp;which point belongs to the child triangle but not the parent triangle. One way we could retrieve this information is by computing the set difference between the vertices belonging to the parent triangle and child triangle, all while carefully keeping track of vertex indices and edge orientation. This certainly works, however, it can be cumbersome to write a brute force combinatorial helper method for each unique mesh element traversal routine.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">The halfedge mesh data structure<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Professor Keenan Crane explained that a popular mesh data structure that allows a scientist to conveniently implement mesh traversal routines is that of the halfedge mesh. At its core a halfedge mesh encodes the connectivity information of a combinatorial surface by keeping track of a set of halfedges and the two connectivity functions known as <em>twin<\/em> and <em>next<\/em>. Here the set of halfedges are none other than the directed edges obtained from an oriented triangle mesh. The twin function takes a halfedge and brings it to its corresponding oppositely oriented twin halfedge. In this fashion, if we apply the twin function to some halfedge twice we get the same initial halfedge back. The next function takes a halfedge and brings it to the next halfedge in the current triangle. In this fashion if we take&nbsp; the next function and apply it to a halfedge belonging to a triangle three times, we get the same initial halfedge back.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/cs184.eecs.berkeley.edu\/cs184_sp16_content\/article_images\/7_.jpg\" alt=\"\" width=\"605\" height=\"387\"\/><figcaption>A diagram depicting the halfedge data structure connectivity relationships. <a href=\"https:\/\/cs184.eecs.berkeley.edu\/sp20\/article\/17\/an-introduction-to-half-edge-dat\" data-type=\"URL\" data-id=\"https:\/\/cs184.eecs.berkeley.edu\/sp20\/article\/17\/an-introduction-to-half-edge-dat\" target=\"_blank\" rel=\"noreferrer noopener\">Source<\/a>.<\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Professor Keenan Crane has a well written introduction to the halfedge data structure in <a rel=\"noreferrer noopener\" href=\"https:\/\/www.cs.cmu.edu\/~kmcrane\/Projects\/DDG\/paper.pdf\" data-type=\"URL\" data-id=\"https:\/\/www.cs.cmu.edu\/~kmcrane\/Projects\/DDG\/paper.pdf\" target=\"_blank\">section 2.5 of his course notes on Discrete Differential Geometry<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It turns out that geometry central uses the halfedge mesh data structure and so we can rewrite the traversal of the adjacent faces loop to more easily retrieve our desired connectivity information. In the geometry central implementation, every mesh element (vertex, edge, face, etc.) contains a reference to a halfedge, and vice versa.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n\/\/ Pop the current Face off the front of the queue\nFace currentFace = visited.front();\nvisited.pop();\n\n\/\/ Get the face\u2019s halfedge\nHalfedge currentHalfedge = currentFace.halfedge();\n\n\/\/ Visit the adjacent faces\ndo\n{\n    \/\/ Get the current adjacent face\n    Face adjFace = currentHalfedge.twin().face();\n    if (!isVisited&#091;adjFace])\n    {\n        \/\/ Retrieve our desired vertices\n        Vertex a = currentHalfedge.vertex();\n        Vertex b = currentHalfedge.next().vertex();\n        Vertex c = currentHalfedge.twin().next().next().vertex();\n\n        \/\/ Calculate the triangle\u2019s flattened vertex positions\n        calculateFlatVertices(a, b, c);\n        \/\/ And push it onto the queue\n        visited.push(adjFace);\n    }\n    \/\/ Iterate to the next halfedge\n    currentHalfEdge = currentHalfEdge.next();\n}\n\/\/ Exit the loop when we reach our starting halfedge\nwhile (currentHalfEdge != currentFace.halfedge());\n\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Here\u2019s a diagram illustrating the relationship between the <code>currentHalfedge<\/code> and vertices <code>a<\/code>, <code>b<\/code>, and <code>c<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"540\" src=\"http:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/halfedge_connectivity-1.png\" alt=\"\" class=\"wp-image-1027\" srcset=\"https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/halfedge_connectivity-1.png 960w, https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/halfedge_connectivity-1-300x169.png 300w, https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/halfedge_connectivity-1-768x432.png 768w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><figcaption>A diagram illustrating the connectivity relationship between the <code>currentHalfedge<\/code> and vertices <code>a<\/code>, <code>b<\/code>, and <code>c<\/code>. Note that  <code>cH<\/code> abbreviates <code>currentHalfedge.<\/code><\/figcaption><\/figure><\/div>\n\n\n\n<h4 class=\"wp-block-heading\">Segfaults, debugging, and ghost faces<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">This all looks great right? Now we need to determine the specifics of calculating the flat vertices? Well, not exactly. When we were running a version of this code in which we attempted to visualize the resulting breadth-first traversal we encountered several random segfaults. When Sahra ran a debugger (shout out to GDB and LLDB \ud83e\udd70) we learned that the culprit was the <code>isVisited[adjFace]<\/code>&nbsp; function call on the line<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nif (!isVisited&#091;adjFace])\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">We were very confused as to why we would be getting a segfault while trying to retrieve the value corresponding to the key <code>adjFace<\/code> contained in the map <code>FaceData&lt;bool&gt; isVisited<\/code>. Sahra inspected the contents of the <code>adjFace<\/code> object and observed that it had index 248 whereas the mesh we were testing the breadth-first search on only had 247 faces. Because C++ zero indexes its elements, this means we somehow retrieved a face with index out of range by 2! How could this have happened? How did we retrieve that face in the first place? Looking at the lines<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n\/\/ Get the current adjacent face\nFace adjFace = currentHalfedge.twin().face();\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">we realized that we made an unsafe assumption about <code>currentHalfedge<\/code>. In particular, we assumed that it was not a boundary edge. What does the twin of a boundary halfedge that has no real twin look like? If the issue we were running to was that the <code>currentHalfedge<\/code> was a boundary halfedge, why didn\u2019t we get a segfault on simply <code>currentHalfedge.twin()<\/code>? Doing some research, we found that the geometry central internals documentation explains that<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-style-default is-layout-flow wp-block-quote-is-layout-flow\"><p>&#8220;We can implicitly encode the <code>twin()<\/code> relationship by storing twinned halfedges adjacent to one another\u2013 that is, the twin of an even-numbered halfedge numbered <code>he<\/code> is <code>he+1<\/code>, and the twin of and odd-numbered halfedge is <code>he-1<\/code>.&#8221;<\/p><cite><a href=\"https:\/\/geometry-central.net\/surface\/surface_mesh\/internals\/\" data-type=\"URL\" data-id=\"https:\/\/geometry-central.net\/surface\/surface_mesh\/internals\/\" target=\"_blank\" rel=\"noreferrer noopener\">Geometry central internals documentation<\/a><\/cite><\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Aha! This explains exactly why <code>currentHalfedge.twin()<\/code> still works on a boundary halfedge; behind the scenes, it is just adding or subtracting one to the halfedge\u2019s index. Where did the face index come from? We\u2019re still unsure, but we realized that the face <code>currentHalfedge.twin().face()<\/code> only makes sense (and hence can only be used as a key for&nbsp;the visited map) when <code>currentHalfedge<\/code> is not a boundary halfedge. Here is a diagram of the &#8220;ghost face&#8221; that we think the line <code>Face adjFace = currentHalfedge.twin().face()<\/code> was producing.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"540\" src=\"http:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/ghost_face.png\" alt=\"A diagram depicting how taking the face of the twin of a boundary halfedge produces a nonexistent face.\" class=\"wp-image-1040\" srcset=\"https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/ghost_face.png 960w, https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/ghost_face-300x169.png 300w, https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/ghost_face-768x432.png 768w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><figcaption>A diagram depicting how taking the face of the twin of a boundary halfedge produces a nonexistent face.<\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Changing the map access line in the if statement to<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nif (!currentHalfedge.edge().isBoundary() &amp;&amp; !isVisited&#091;adjFace])\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">resolved the segfaults and produced a working breadth-first traversal. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conformal parameterization<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here is a picture illustrating applying the flattening algorithm to a model of a cat head.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-25-at-3.29.46-PM-1024x561.png\" alt=\"\" class=\"wp-image-1278\" width=\"610\" height=\"334\" srcset=\"https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-25-at-3.29.46-PM-1024x561.png 1024w, https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-25-at-3.29.46-PM-300x164.png 300w, https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-25-at-3.29.46-PM-768x421.png 768w, https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-25-at-3.29.46-PM-1536x842.png 1536w, https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-25-at-3.29.46-PM-2048x1123.png 2048w, https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-25-at-3.29.46-PM-1200x658.png 1200w, https:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-25-at-3.29.46-PM-1980x1085.png 1980w\" sizes=\"auto, (max-width: 610px) 100vw, 610px\" \/><figcaption>A picture illustrating the application of the flattening algorithm to a model of a cat head.<\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">You can see that there are many cracks and this is because the model of the cat head is not flat\u2014in particular, it has vertices with nonzero angle defect. A vertex angle defect for a given vertex is equal to the difference between \\(2 \\pi\\) and the sum of the corner angles containing that vertex. This is a good measure of how flat a vertex is because for a perfectly flat vertex, all angles surrounding it will sum to \\(2 \\pi\\).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After laying out the edges on the plane \\(z=0\\), we began the necessary steps to compute a <em>conformal flattening<\/em> (an angle-preserving parameterization). In order to complete this step, we needed to find a set of new edge lengths which would both be related to the original ones by a scale factor and minimize the angle defects,<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\">\\(l_{ij} := \\sqrt{ \\phi_i \\phi_j} l_{ij}^0, \\quad \\forall ij \\in E\\),<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">where where \\(l_{ij}\\) is the new intrinsic edge length, \\(\\phi_i, \\phi_j\\) are the scale factors at vertices \\(i, j\\), and \\(l_{ij}^0\\) is the initial edge length.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Discrete Yamabe flow<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">At this stage, we have a clear goal: to optimize the scale factors in order to scale the edge lengths and minimize the angle defects across the mesh (i.e. fully flatten the mesh). From here, we use the <em>discrete<\/em> <em>Yamabe flow <\/em>to meet both of these requirements. Before implementing this algorithm, we began by substituting the scale factors with their logarithms<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\">\\(l_{ij} = e^{(u_i + u_j)\/2} l_{ij}^0\\),<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">where \\(l_{ij}\\) is the new intrinsic edge length, \\(u_i, u_j\\) are the scale factors at vertices \\(i, j\\), and \\(l_{ij}^0\\) is the initial edge length. This ensures the new intrinsic edge lengths are always positive and that the optimization is convex.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To implement the algorithm, we followed this procedure:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1. Calculate the initial edge lengths<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2. While all angle defects are below a certain threshold epsilon:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Compute the scaled edge lengths<\/li><li>Compute the current angle defects based on the new interior angles based on the scaled edge lengths<\/li><li>Update the scale factors using the step and the angle defects:<\/li><\/ul>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\">\\(u_i \\leftarrow u_i &#8211; h \\Omega _i\\),<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">where \\(u_i\\) is the scale factor of the \\(i\\)th vertex, \\(h\\) is the gradient descent step size, and \\(\\Omega_i\\) is the intrinsic angle defect at the \\(i\\)th vertex.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After running this algorithm and displaying the result, we found that we were able to obtain a perfect conformal flattening of the input mesh (there were no cracks!). There was one issue, however: we needed to manually choose a step size that would work well for the chosen epsilon value. Our next step was to extend our current algorithm by implementing a <em>backtracking line search<\/em> which would change the step size based on the energy.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Results<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here are two videos demonstrating the Yamabe flow algorithm. The first video illustrates how each iteration of the flow improves the flattened mesh and the second video illustrates how that translates into UV coordinates for texture mapping. We are really happy with how these turned out!<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter\"><video height=\"1436\" style=\"aspect-ratio: 2550 \/ 1436;\" width=\"2550\" controls src=\"http:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/yamabeFlow_cathead_2d.mov\"><\/video><figcaption>A video visualizing intermediate 2D parameterizations produced by the Yamabe flow.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-video aligncenter\"><video height=\"1436\" style=\"aspect-ratio: 2550 \/ 1436;\" width=\"2550\" controls src=\"http:\/\/summergeometry.org\/sgi2021\/wp-content\/uploads\/2021\/08\/yamabeFlow_cathead_3d.mov\"><\/video><figcaption>A video visualizing the intermediate UV coordinates on the cat head mesh produced by the Yamabe flow<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Line search<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To implement this, we added a sub-loop to our existing Yamabe flow procedure which repeatedly test smaller step sizes until one is found which will decrease the energy, e.g., backtracking line search. A good resource on this topic is Stephen Boyd, Stephen P Boyd, and Lieven Vandenberghe. Convex optimization. Cambridge university press, 2004. After resolving a bug in which our step size would stall at very small values with no progress, we were successful in implementing this line search. Now, a large step size could be given without missing the minima.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Newton\u2019s method<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, we worked on using <em>Newton\u2019s method<\/em> to improve the descent direction by changing the gradient to more easily reach the minimum. To complete this, we needed to calculate the Hessian &#8212; in this case, the Hessian of the discrete conformal energy was the cotan-Laplace matrix \\(L\\). This matrix had square dimensions (the number of rows and the number of columns was equal to the number of interior vertices) and has off-diagonal entries:<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\">\\(L_{ij} = -\\frac{1}{2} (\\cot \\theta_k ^{ij} + \\cot \\theta _k ^{ji})\\)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">for each edge \\(ij\\), as well as diagonal entries<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\">\\(L_{ii} = &#8211; \\sum _{ij} L_{ij}\\)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">for each edge \\(ij\\) incident to the \\(i\\)th vertex.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The newton&#8217;s descent algorithm is as follows:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>First, build the cotan-Laplace matrix L based on the above definitions<\/li><li>Determine the descent direction \\(\\dot{u} \\in \\mathbb{R}^{|V_{\\text{int}}|}\\), by solving the system \\(L \\dot{u} = &#8211; \\Omega\\) with \\(\\Omega \\in \\mathbb{R}^{|V_{\\text{int}}|}\\).as the vector containing all of the angle defects at interior vertices.<\/li><li>Run line search again, but with \\(\\dot{u}\\) replacing \\(&#8211; \\Omega\\) as the search direction.<\/li><\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">This method yielded a completely flat mesh with no cracks. Newton\u2019s method was also significantly faster: on one of our machines, Newton\u2019s method took 3 ms to compute a crack-free parameterization for the cat head model while the original Yamabe flow implementation took 58 ms.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>By Joana Portmann, Tal Rastopchin, and Sahra Yusuf.Mentored by Professor Keenan Crane. Intrinsic parameterization During these last two weeks, we explored intrinsic encoding of triangle meshes. As an introduction to this new topic, we wrote a very simple algorithm that lays out a triangle mesh flat. We then improved this algorithm via line search over [&hellip;]<\/p>\n","protected":false},"author":14,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[25],"tags":[79,80,78],"class_list":["post-998","post","type-post","status-publish","format-standard","hentry","category-sgi-research-projects","tag-intrinsic-geometry","tag-newtons-method","tag-parameterization"],"_links":{"self":[{"href":"https:\/\/summergeometry.org\/sgi2021\/wp-json\/wp\/v2\/posts\/998","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/summergeometry.org\/sgi2021\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/summergeometry.org\/sgi2021\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/summergeometry.org\/sgi2021\/wp-json\/wp\/v2\/users\/14"}],"replies":[{"embeddable":true,"href":"https:\/\/summergeometry.org\/sgi2021\/wp-json\/wp\/v2\/comments?post=998"}],"version-history":[{"count":10,"href":"https:\/\/summergeometry.org\/sgi2021\/wp-json\/wp\/v2\/posts\/998\/revisions"}],"predecessor-version":[{"id":1281,"href":"https:\/\/summergeometry.org\/sgi2021\/wp-json\/wp\/v2\/posts\/998\/revisions\/1281"}],"wp:attachment":[{"href":"https:\/\/summergeometry.org\/sgi2021\/wp-json\/wp\/v2\/media?parent=998"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/summergeometry.org\/sgi2021\/wp-json\/wp\/v2\/categories?post=998"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/summergeometry.org\/sgi2021\/wp-json\/wp\/v2\/tags?post=998"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}