{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tetrahedral Mesh" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from lapy import TetMesh" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First, instead of loading, we define a small tetrahedral mesh representing a cube with a center vertex and twelve tetrahedra." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# cube9 (cube with center node)\n", "points = [[0,0,0], [1,0,0], [1,1,0], [0,1,0], [0,0,1],\n", " [1,0,1], [1,1,1], [0,1,1], [0.5,0.5,0.5]]\n", "tets = [[0,5,8,1], [0,4,5,8], [2,5,6,8], [1,5,2,8],\n", " [6,7,3,8], [6,3,2,8], [0,3,4,8], [3,7,4,8],\n", " [0,1,2,8], [0,2,3,8], [4,6,5,8], [4,7,6,8]]\n", "T = TetMesh(points,tets)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note, that we flipped the first tetrahedron vertex order on purpose (it should be 0,5,1,8) to test and correct orientation below." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can check if our tet mesh has free vertices (these are vertices that are not used in any tetrahedron)." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "T.has_free_vertices()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "No free vertices are found, so we cannot remove any and the attempt will keep all 9." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(array([0, 1, 2, 3, 4, 5, 6, 7, 8]), [])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "T.rm_free_vertices_()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's see next, if we have consistent orientations (this should fail)." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Orientations are not uniform\n" ] }, { "data": { "text/plain": [ "False" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "T.is_oriented()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some functions don't care about the orientation, for example the average edge length computation." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0543647924813107" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "T.avg_edge_length()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also get the boundary of the tet mesh as a triangle mesh." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Found 12 triangles on boundary.\n" ] } ], "source": [ "BT = T.boundary_tria()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But also the boundary is not oriented consistently (triangle normals of neighboring triangles point in opposite directions)." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "BT.is_oriented()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's repeat those steps after correcting the orientation in the tet mesh." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Flipped 1 tetrahedra\n", "All tet orientations are correct\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "T.orient_()\n", "T.is_oriented()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When we extract the boundary surface now, we see it is also consistently oriented." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Found 12 triangles on boundary.\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "BT = T.boundary_tria()\n", "BT.is_oriented()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Correct orientation is needed, e.g., to compute the volume of a surface mesh." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "BT.volume()" ] } ], "metadata": { "kernelspec": { "display_name": "Python3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3" } }, "nbformat": 4, "nbformat_minor": 4 }