Disabled external gits

This commit is contained in:
2022-04-07 18:46:57 +02:00
parent 88cb3426ad
commit 15e7120d6d
5316 changed files with 4563444 additions and 6 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,482 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"id": "47a1752b-1db4-4004-9991-164388c0fd5d",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import meshplot as mp"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "0f4900fe-ce65-410a-b8d3-088e7e0804a5",
"metadata": {},
"outputs": [],
"source": [
"import igl\n",
"import scipy as sp\n",
"import numpy as np\n",
"from meshplot import plot, subplot, interact\n",
"import time\n",
"import copy\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "9c83b851-d0aa-4fb0-9030-a285ca6b2b64",
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"sys.path.append('../src')"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "43cb9cef-4959-4c9b-98ef-3a603f57bcb2",
"metadata": {},
"outputs": [],
"source": [
"import importlib, utils, laplacian_utils, mean_curvature_flow, remesher_helper\n",
"importlib.reload(utils)\n",
"importlib.reload(laplacian_utils)\n",
"importlib.reload(mean_curvature_flow)\n",
"importlib.reload(remesher_helper)\n",
"from utils import parse_input_mesh, normalize_area, get_diverging_colors, remesh\n",
"from mean_curvature_flow import MCF"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "2570faf5-9582-42ac-ace4-ca82c781a806",
"metadata": {},
"outputs": [],
"source": [
"epsilon1 = 5e-2\n",
"epsilon2 = 1e-3\n",
"mesh_color = np.array([0,0.7,1])"
]
},
{
"cell_type": "markdown",
"id": "e8d2f669-864f-4c8e-8519-5672862cc024",
"metadata": {},
"source": [
"### Example 1"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "7a65d5c7-d774-4d5a-946c-69d730f19519",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"v1, f1, num_bdry_vx, num_intr_vx = parse_input_mesh(\"../data/two_rings_remesh.obj\")\n",
"curr_mcf = MCF(num_bdry_vx, num_intr_vx)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "a82f1487-56e3-4ecb-b71c-b3f59d4070be",
"metadata": {
"tags": []
},
"outputs": [
{
"ename": "TypeError",
"evalue": "unsupported operand type(s) for /: 'NoneType' and 'NoneType'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m/tmp/ipykernel_12039/3840203228.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mstart\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mvs1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maverage_mean_curvature_list1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcurr_mcf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun_mean_curvature_flow\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1000\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5e-2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1e-3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Run {} iterations of unstable mean curvature flow\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0maverage_mean_curvature_list1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"took {} seconds\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0mstart\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/opt/notebooks/assignment_3_2/notebook/../src/mean_curvature_flow.py\u001b[0m in \u001b[0;36mrun_mean_curvature_flow\u001b[0;34m(self, v, f, max_iter, epsilon1, epsilon2)\u001b[0m\n\u001b[1;32m 83\u001b[0m \u001b[0mYour\u001b[0m \u001b[0mcode\u001b[0m \u001b[0mhere\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 84\u001b[0m '''\n\u001b[0;32m---> 85\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msolve_laplace_equation\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 86\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate_system\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 87\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/opt/notebooks/assignment_3_2/notebook/../src/mean_curvature_flow.py\u001b[0m in \u001b[0;36msolve_laplace_equation\u001b[0;34m(self, v, f)\u001b[0m\n\u001b[1;32m 44\u001b[0m '''\n\u001b[1;32m 45\u001b[0m \u001b[0;31m# Construct the LHS and RHS of the linear solve.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 46\u001b[0;31m \u001b[0mlhs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mL\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mM\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnum_bdry_vx\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 47\u001b[0m \u001b[0mrhs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mzeros\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnum_intr_vx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for /: 'NoneType' and 'NoneType'"
]
}
],
"source": [
"start = time.time()\n",
"vs1, average_mean_curvature_list1 = curr_mcf.run_mean_curvature_flow(v1, f1, 1000, 5e-2, 1e-3)\n",
"print(\"Run {} iterations of unstable mean curvature flow\".format(len(average_mean_curvature_list1)))\n",
"print(\"took {} seconds\".format(time.time() - start))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "652d1fa7-ad74-4c50-85c1-6a9e622b7ec8",
"metadata": {},
"outputs": [],
"source": [
"plt.plot(average_mean_curvature_list1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "14411752-e879-40f4-a3ce-928cfa2e888e",
"metadata": {},
"outputs": [],
"source": [
"p1 = mp.plot(vs1[0], f1, shading={\"wireframe\": False,\"width\": 900, \"height\": 600}, return_plot=True, c=mesh_color)\n",
"\n",
"@interact(level=(0, len(vs1)-1))\n",
"def mcf(level=0):\n",
" p1.update_object(vertices=vs1[level])"
]
},
{
"cell_type": "markdown",
"id": "baf4bc95-68df-4a4b-967f-a2b555d4947c",
"metadata": {},
"source": [
"### Example 2"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "147b044e-4491-4e45-bf91-df58f870429f",
"metadata": {},
"outputs": [],
"source": [
"v2, f2, num_bdry_vx, num_intr_vx = parse_input_mesh(\"../data/half_cube_remesh.obj\")\n",
"curr_mcf = MCF(num_bdry_vx, num_intr_vx)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dbc8d3df-ac70-4c75-a6e7-d624595d5a59",
"metadata": {},
"outputs": [],
"source": [
"start = time.time()\n",
"vs2, average_mean_curvature_list2 = curr_mcf.run_mean_curvature_flow(v2, f2, 1000, epsilon1, epsilon2)\n",
"print(\"Run {} iterations of unstable mean curvature flow\".format(len(average_mean_curvature_list2)))\n",
"print(\"took {} seconds\".format(time.time() - start))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "87c6c46b-36e4-4206-96da-b3f10d897387",
"metadata": {},
"outputs": [],
"source": [
"plt.plot(average_mean_curvature_list2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "db07878e-9438-413d-9eb5-a2ffb8f02118",
"metadata": {},
"outputs": [],
"source": [
"p2 = mp.plot(vs2[0], f2, shading={\"wireframe\": False, \"flat\": True}, c=mesh_color)\n",
"\n",
"@interact(level=(0, len(vs2)-2))\n",
"def mcf(level=0):\n",
" p2.update_object(vertices=vs2[level])"
]
},
{
"cell_type": "markdown",
"id": "613b0257-40c3-4f8f-8840-ea9dccccefa9",
"metadata": {},
"source": [
"### Example 3"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ddd60020-bc75-4984-937f-ab30359b559c",
"metadata": {},
"outputs": [],
"source": [
"v3, f3, num_bdry_vx, num_intr_vx = parse_input_mesh(\"../data/cube_remesh.obj\")\n",
"curr_mcf = MCF(num_bdry_vx, num_intr_vx)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "661c1cfb-3ac6-434a-b385-a94be86f2802",
"metadata": {},
"outputs": [],
"source": [
"start = time.time()\n",
"vs3, average_mean_curvature_list3 = curr_mcf.run_mean_curvature_flow(v3, f3, 1000, epsilon1, epsilon2)\n",
"print(\"Run {} iterations of unstable mean curvature flow\".format(len(average_mean_curvature_list3)))\n",
"print(\"took {} seconds\".format(time.time() - start))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "06d71f4a-214a-4fbc-84ee-aad174ac104f",
"metadata": {},
"outputs": [],
"source": [
"plt.plot(average_mean_curvature_list3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4e3faeb6-3f38-43d1-a4a0-047b62e11bf3",
"metadata": {},
"outputs": [],
"source": [
"p3 = mp.plot(vs3[0], f3, shading={\"wireframe\": False, \"flat\": True}, c=mesh_color)\n",
"\n",
"@interact(level=(0, len(vs3)-2))\n",
"def mcf(level=0):\n",
" p3.update_object(vertices=vs3[level])"
]
},
{
"cell_type": "markdown",
"id": "d92f7eea-e7f0-4a92-b557-21637eb7f939",
"metadata": {},
"source": [
"## Your Own Minimal Surface!"
]
},
{
"cell_type": "markdown",
"id": "242feed4-775d-4c68-aadb-707382dde2f5",
"metadata": {},
"source": [
"### Visualize your blender output\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "105532b3-69ab-4835-9768-5a03df5051af",
"metadata": {},
"outputs": [],
"source": [
"blender_input_filename = \"../data/mesh.obj\""
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "c9e2c901-d3f9-4a2f-bb3b-27a8be7b2311",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Warning: readOBJ() ignored non-comment line 3:\n",
" o BezierCircle.002_Mesh.002\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "c3305f3372914f049d1f00b95e75db4c",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Renderer(camera=PerspectiveCamera(aspect=1.5, children=(DirectionalLight(color='white', intensity=0.6, positio…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"v,f = igl.read_triangle_mesh(blender_input_filename)\n",
"p1 = plot(v, f, shading={\"wireframe\": True,\"width\": 900, \"height\": 600}, return_plot=True, c=mesh_color)"
]
},
{
"cell_type": "markdown",
"id": "264e0ee7-8a7d-44b0-8221-fc15b38ce77e",
"metadata": {},
"source": [
"### Remesh"
]
},
{
"cell_type": "markdown",
"id": "b6905f01-bc8b-4421-b2fb-5fa2b0b79a90",
"metadata": {},
"source": [
"The input should be a triangle mesh or a quad mesh. This might takes a while depends on your design. You can adjust the `mesh_size` parameter in the `remesh` function."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "4ba2345b-dac3-45e6-a28e-123929f70b93",
"metadata": {
"scrolled": true,
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Info : Classifying surfaces (angle: 180)...\n",
"Info : Splitting triangulations to make them parametrizable:\n",
"Info : - Level 0 partition with 3978 triangles split in 2 parts because poincare characteristic 2 is not 0\n",
"Info : Model has 0 non manifold mesh edges and 3786 boundary mesh edges\n",
"Info : Found 2 model surfaces\n",
"Info : Found 3 model curves\n",
"Info : Done classifying surfaces (Wall 0.0693158s, CPU 0.069573s)\n",
"Info : Creating geometry of discrete curves...\n",
"Info : Done creating geometry of discrete curves (Wall 0.000228139s, CPU 0.000371s)\n",
"Info : Creating geometry of discrete surfaces...\n",
"Info : [ 0%] Creating geometry \r",
"Info : [ 50%] Creating geometry \r",
"Info : Done creating geometry of discrete surfaces (Wall 0.0322831s, CPU 0.032606s)\n",
"Info : Meshing 1D...\n",
"Info : [ 0%] Meshing curve 5 (Discrete curve)\n",
"Info : [ 20%] Meshing curve 6 (Discrete curve)\n",
"Info : [ 40%] Meshing curve 7 (Discrete curve)\n",
"Info : [ 50%] Meshing curve 8 (Discrete curve)\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Warning : Poor input mesh quality (min gamma = 0.000204069) for computing parametrization\n",
"Warning : Poor input mesh quality (min gamma = 0.000204069) for computing parametrization\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Info : [ 70%] Meshing curve 9 (Discrete curve)\n",
"Info : [ 90%] Meshing curve 10 (Discrete curve)\n",
"Info : Done meshing 1D (Wall 0.100252s, CPU 0.100165s)\n",
"Info : Meshing 2D...\n",
"Info : [ 0%] Meshing surface 2 (Discrete surface, Frontal-Delaunay)\n",
"Info : [ 0%] Meshing surface 2 (Discrete surface, MeshAdapt)\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Warning : 4752 elements remain invalid in surface 2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Info : [ 50%] Meshing surface 3 (Discrete surface, Frontal-Delaunay)\n",
"Info : Done meshing 2D (Wall 20.1908s, CPU 20.176s)\n",
"Info : 12214 nodes 24512 elements\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Warning : ------------------------------\n",
"Warning : Mesh generation error summary\n",
"Warning : 1 warning\n",
"Warning : 0 errors\n",
"Warning : Check the full log for details\n",
"Warning : ------------------------------\n"
]
}
],
"source": [
"remesh_output_name = \"../data/remesh.obj\"\n",
"remesh(blender_input_filename, remesh_output_name)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "245e2f45-c1ee-4f9f-86cd-e7fd9a0404de",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "ddb1c83810f241d69cfb63f6c5fda32e",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Renderer(camera=PerspectiveCamera(aspect=1.5, children=(DirectionalLight(color='white', intensity=0.6, positio…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"v,f = igl.read_triangle_mesh(remesh_output_name)\n",
"p2 = plot(v, f, shading={\"wireframe\": True,\"width\": 900, \"height\": 600}, return_plot=True, c=mesh_color)"
]
},
{
"cell_type": "markdown",
"id": "117e73d7-f291-4aa1-b783-cf8e2ae70a21",
"metadata": {},
"source": [
"### Run optimization"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "632ea182-feb9-46b0-b2b5-83b32e65f9b7",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -0,0 +1,375 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "bcb9c6df-0417-4d0a-9990-185ce07b918b",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import meshplot as mp"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "45981306-4fde-431e-9240-3d153a016863",
"metadata": {},
"outputs": [],
"source": [
"import igl\n",
"import scipy as sp\n",
"import numpy as np\n",
"from meshplot import plot, subplot, interact\n",
"import time\n",
"import copy\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "c39ddea4-e782-4c2b-a942-ec11610a4ceb",
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"sys.path.append('../src')"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f58fb451-bdcf-49d7-a928-4992ab599761",
"metadata": {},
"outputs": [],
"source": [
"import importlib, utils, laplacian_utils, mean_curvature_flow, remesher_helper\n",
"importlib.reload(utils)\n",
"importlib.reload(laplacian_utils)\n",
"importlib.reload(mean_curvature_flow)\n",
"importlib.reload(remesher_helper)\n",
"from utils import parse_input_mesh, normalize_area, get_diverging_colors, plot_directions\n",
"from mean_curvature_flow import MCF\n",
"import smooth_surfaces"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "bb26ed62-f404-437f-977a-8ff22a19f840",
"metadata": {},
"outputs": [],
"source": [
"from fitting import compute_mesh_principal_curvatures"
]
},
{
"cell_type": "markdown",
"id": "8b12d84d-06a1-4315-87b2-d8bb4a6b4360",
"metadata": {},
"source": [
"### Closed Surface Example"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "cf187b60-2fbf-4f0b-9924-efe4939bafae",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Warning: readOBJ() ignored non-comment line 3:\n",
" o Mesh\n"
]
}
],
"source": [
"v, f, num_bdry_vx, num_intr_vx = parse_input_mesh(\"../data/bob_tri.obj\")\n",
"curr_mcf = MCF(num_bdry_vx, num_intr_vx)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "dcf12908-b20c-4a1c-adcf-492d23a54011",
"metadata": {},
"outputs": [],
"source": [
"k1, k2, d1, d2 = compute_mesh_principal_curvatures(v, f)"
]
},
{
"cell_type": "markdown",
"id": "b3294e38-ccac-4fbc-8661-71403e472cc6",
"metadata": {},
"source": [
"### Gaussian Curvature"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "cf601268-72af-4964-940d-211719f3123c",
"metadata": {},
"outputs": [
{
"ename": "TypeError",
"evalue": "unsupported operand type(s) for +: 'NoneType' and 'NoneType'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m/tmp/ipykernel_12120/1640637150.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mgaussian_curvature\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mk1\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0mk2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mgaussian_curvature\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0mnum_bdry_vx\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m*=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mgp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mplot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mget_diverging_colors\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgaussian_curvature\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'NoneType' and 'NoneType'"
]
}
],
"source": [
"gaussian_curvature = k1+k2\n",
"gaussian_curvature[:num_bdry_vx] *= 0\n",
"gp = mp.plot(v, f, get_diverging_colors(gaussian_curvature))"
]
},
{
"cell_type": "markdown",
"id": "4a3a46af-15b0-4b8c-afd4-14159774a646",
"metadata": {},
"source": [
"### Mean Curvature"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "003d4541-fff5-414d-bacf-36a8a45fb412",
"metadata": {},
"outputs": [],
"source": [
"mean_curvature = (k1+k2)/2\n",
"mean_curvature[:num_bdry_vx] *= 0\n",
"gp = mp.plot(v, f, get_diverging_colors(mean_curvature))"
]
},
{
"cell_type": "markdown",
"id": "3e30eb7f-4c81-461a-a9db-c1df00eb30ec",
"metadata": {},
"source": [
"### Principal Curvature Direction"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "433424ef-f93c-485f-9929-17b84fd96026",
"metadata": {},
"outputs": [],
"source": [
"plot_directions(v, f, d1, d2, scale=0.08)"
]
},
{
"cell_type": "markdown",
"id": "5a8c19a9-a4ff-4fcf-99f8-017c4cc97b7b",
"metadata": {},
"source": [
"### Asymptotic Direction"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "08194caa-c825-4445-afcb-c11ae7c87b10",
"metadata": {},
"outputs": [],
"source": [
"a1, a2 = smooth_surfaces.compute_asymptotic_directions(k1, k2, d1, d2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d2b75928-f37e-4342-bebc-bcf00fcd9fbb",
"metadata": {},
"outputs": [],
"source": [
"plot_directions(v, f, a1, a2, scale=0.08)"
]
},
{
"cell_type": "markdown",
"id": "c6675cc3-281d-4de0-96e9-b679c19bea56",
"metadata": {},
"source": [
"## Minimal Surface Example"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10519def-3402-401f-ad08-8c2e120d11e2",
"metadata": {},
"outputs": [],
"source": [
"epsilon1 = 5e-2\n",
"epsilon2 = 1e-3"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9d97b409-968f-4398-a28e-749ae1af28d3",
"metadata": {},
"outputs": [],
"source": [
"v2, f2, num_bdry_vx, num_intr_vx = parse_input_mesh(\"../data/two_rings_remesh.obj\")\n",
"curr_mcf = MCF(num_bdry_vx, num_intr_vx)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "887806bf-1c10-44b7-b0f8-acd398187678",
"metadata": {},
"outputs": [],
"source": [
"start = time.time()\n",
"vs, average_mean_curvature_list1 = curr_mcf.run_mean_curvature_flow(v2, f2, 1000, epsilon1, epsilon2)\n",
"print(\"Run {} iterations of unstable mean curvature flow\".format(len(average_mean_curvature_list1)))\n",
"print(\"took {} seconds\".format(time.time() - start))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d0cd92a5-8848-4a7e-9b93-34b4b9d0967b",
"metadata": {},
"outputs": [],
"source": [
"k1, k2, d1, d2 = compute_mesh_principal_curvatures(vs[-1], f2)"
]
},
{
"cell_type": "markdown",
"id": "6c3bb956-62d0-43f7-a0a0-30571933c97a",
"metadata": {},
"source": [
"### Gaussian Curvature"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "785540b8-03ed-4620-9a8f-ad7f9ec4d154",
"metadata": {},
"outputs": [],
"source": [
"gaussian_curvature = k1+k2\n",
"gaussian_curvature[:num_bdry_vx] *= 0\n",
"gp = mp.plot(vs[-1], f2, get_diverging_colors(gaussian_curvature, percentile=80))"
]
},
{
"cell_type": "markdown",
"id": "a84dcd14-6dd4-44fe-93e8-440d78127643",
"metadata": {},
"source": [
"### Mean Curvature"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b3333375-fc84-4e10-85e0-5b744a3e585a",
"metadata": {},
"outputs": [],
"source": [
"mean_curvature = (k1+k2)/2\n",
"mean_curvature[:num_bdry_vx] *= 0\n",
"gp = mp.plot(vs[-1], f2, get_diverging_colors(mean_curvature))"
]
},
{
"cell_type": "markdown",
"id": "4345e08f-cd16-4644-915d-270d5788bf88",
"metadata": {
"tags": []
},
"source": [
"### Principal Curvature Direction"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d7b85256-915e-489f-ad7b-f9d2faa9036f",
"metadata": {},
"outputs": [],
"source": [
"plot_directions(vs[-1], f2, d1, d2, scale=0.08)"
]
},
{
"cell_type": "markdown",
"id": "8f7831fe-b870-4ee5-b1e8-6a1081bd17f7",
"metadata": {},
"source": [
"### Asymptotic Direction"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9674731a-d083-46cf-8ddd-f135538e8217",
"metadata": {},
"outputs": [],
"source": [
"a1, a2 = smooth_surfaces.compute_asymptotic_directions(k1, k2, d1, d2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "634c2079-e22a-4458-a126-851a87562015",
"metadata": {},
"outputs": [],
"source": [
"plot_directions(v2, f2, a1, a2, scale=0.08)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8fd20a1f-fa62-4762-9697-864874c55a7a",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,221 @@
import numpy as np
from scipy import sparse
from scipy.sparse import linalg
import igl
from smooth_surfaces import *
from utils import *
# -----------------------------------------------------------------------------
# UTILITIES
# -----------------------------------------------------------------------------
def compute_orthogonal_frames(N):
"""Computes an orthonormal frame {e1, e2, e3} at vertices x_i.
Parameters:
- N : np.array (|n|, 3)
The i-th row contains a vector in direction e3 at x_i.
Returns:
- e1: np.array (|n|, 3)
The i-th row contains the axis e1 at vertex x_i.
- e2: np.array (|n|, 3)
The i-th row contains the axis e2 at vertex x_i.
- e3: np.array (|n|, 3)
The i-th row contains the axis e3 at vertex x_i.
"""
e3 = N / np.linalg.norm(N, axis=1, keepdims=True)
e1 = np.zeros(e3.shape)
e1[:, 0] = - e3[:, 1]
e1[:, 1] = e3[:, 0]
e1[np.where((e1[:, 0] == 0) & (e1[:, 1] == 0))[0], 1] = 1
e1 = e1 / np.linalg.norm(e1, axis=1, keepdims=True)
e2 = np.cross(e3, e1)
return e1, e2, e3
def vertex_double_rings(F):
"""Computes double rings of mesh vertices.
Parameters:
- F : np.array (|F|, 3)
The array of triangle faces.
Returns:
- v_i : np.array (n, )
The indices of the central vertices i.
- v_j : np.array (n, )
The indices of the vertices j connected to vertex i by at most two
edges, such that v_j[k] belongs to the double ring of v_i[k].
"""
M = igl.adjacency_matrix(F)
vi, vj = M.nonzero()
N = M[vj]
vii, vjj = N.nonzero()
L = sparse.coo_matrix((np.ones(len(vii)), (vii, np.arange(len(vii)))))
k = np.array(L.sum(axis=1)).flatten().astype('i')
vii = np.repeat(vi, k)
M = sparse.coo_matrix((np.ones(len(vii)), (vii, vjj)), shape=M.shape)
M = M.tolil()
M.setdiag(0)
return M.nonzero()
# -----------------------------------------------------------------------------
# OSCULATING PARABOLOID
# -----------------------------------------------------------------------------
def compute_osculating_paraboloids(V, F, e1, e2, e3):
"""Computes the coefficients of the osculating paraboloid at vertices x_i
in local orthonormal coordinates with base {x_i; e1, e2, e3}, with
eta(x,y) = a x^2 + b y^2 + c xy + d x + e y
through least squares fitting. Try to vectorize this function.
Parameters:
- V : np.array (|V|, 3)
The array of vertices positions.
Contains the global coordinates of the vertex x_i in i-th row
- F : np.array (|F|, 3)
The array of triangle faces.
- e1: np.array (|V|, 3)
The i-th row contains the axis e1 at vertex x_i.
- e2: np.array (|V|, 3)
The i-th row contains the axis e2 at vertex x_i.
- e3: np.array (|V|, 3)
The i-th row contains the axis e3 at vertex x_i.
Returns:
- a : np.array (|V|, 5)
The paraboloid coefficients. i-th row contains the coefficients
[a, b, c, d, e] of the paraboloid at x_i.
"""
# we compute the indices for the double ring vj at each vertex vi
vi, vj = vertex_double_rings(F)
Pj = V[vj] - V[vi]
x = np.einsum('ij,ij->i',Pj, e1[vi])
y = np.einsum('ij,ij->i',Pj, e2[vi])
z = np.einsum('ij,ij->i',Pj, e3[vi])
i = np.arange(vj.shape[0])
i = np.hstack((i,i,i,i,i))
j = 5*vi
j = np.hstack((j,j+1,j+2,j+3,j+4))
data = np.hstack((x**2, y**2, x*y, x,y))
X = sparse.coo_matrix((data,(i,j)), shape=(vj.shape[0],5*len(V)))
X = X.tocsr()
A = X.T.dot(X)
b = X.T.dot(z)
a = sparse.linalg.spsolve(A,b)
a = np.reshape(a,(len(V),5))
return a
def compute_osculating_paraboloid_first_derivatives(a):
"""Computes the first derivatives of the osculating paraboloid at vertices x_i
in local orthonormal coordinates with base {x_i; e1, e2, e3}, with
eta(x,y) = a x^2 + b y^2 + c xy + d x + e y,
evaluated at the point x_i. Try to vectorize this function.
Parameters:
- a : np.array (|V|, 5)
The paraboloid coefficients. i-th row contains the coefficients
[a, b, c, d, e] of the paraboloid at x_i.
Returns:
- x_x : np.array (|V|, 3)
The first derivatives x_x, where the i-th row contains the local (x,y,z)
coordinates of the vector x_x(x_i).
- x_y : np.array (|V|, 3)
The second derivatives x_y, where the i-th row contains the local (x,y,z)
coordinates of the vector x_y(x_i).
"""
x_x = np.column_stack((np.ones(len(a)), np.zeros(len(a)), a[:,3]))
x_y = np.column_stack((np.zeros(len(a)), np.ones(len(a)), a[:,4]))
return x_x, x_y
def compute_osculating_paraboloid_second_derivatives(a):
"""Computes the second derivatives of the osculating paraboloid at vertices x_i
in local orthonormal coordinates with base {x_i; e1, e2, e3}, with
eta(x,y) = a x^2 + b y^2 + c xy + d x + e y,
evaluated at the point x_i. Try to vectorize this function.
Parameters:
- a : np.array (|V|, 5)
The paraboloid coefficients. i-th row contains the coefficients
[a, b, c, d, e] of the paraboloid at x_i.
Returns:
- x_xx : np.array (|V|, 3)
The second derivatives x_xx, where the i-th row contains the local (x,y,z)
coordinates of the vector x_xx(x_i).
- x_xy : np.array (|V|, 3)
The second derivatives x_xy, where the i-th row contains the local (x,y,z)
coordinates of the vector x_xy(x_i).
- x_yy : np.array (|V|, 3)
The second derivatives x_yy, where the i-th row contains the local (x,y,z)
coordinates of the vector x_yy(x_i).
"""
x_xx = np.column_stack((np.zeros(len(a)), np.zeros(len(a)), 2*a[:,0]))
x_xy = np.column_stack((np.zeros(len(a)), np.zeros(len(a)), a[:,2]))
x_yy = np.column_stack((np.zeros(len(a)), np.zeros(len(a)), 2*a[:,1]))
return x_xx, x_xy, x_yy
def compute_mesh_principal_curvatures(V, F):
"""Computes the principal curvatures at mesh vertices v_i through quadratic
fitting.
Parameters:
- V : np.array (|V|, 3)
The array of vertices positions.
Contains the global coordinates of the vertex x_i in i-th row
- F : np.array (|F|, 3)
The array of triangle faces.
Returns:
- k_1 : np.array (n)
The min principal curvature. i-th element contains the curvature
at vertex x_i.
- k_2 : np.array (n)
The max principal curvature. i-th element contains the curvature
at vertex x_i.
- d_1 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_1.
The i-th row contains the global coordinates of d_1(x_i).
- d_2 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_2.
The i-th row contains the global coordinates of d_2(x_i).
"""
# we compute a vertex normal with libigl and use it as local axis e3:
N = igl.per_vertex_normals(V, F)
# then we compute the local axes:
e1, e2, e3 = compute_orthogonal_frames(N)
# TODO: fill the function. Use the functions implemented in assignment 3.1
a = compute_osculating_paraboloids(V,F,e1,e2,e3)
x_x, x_y = compute_osculating_paraboloid_first_derivatives(a)
x_xx, x_xy, x_yy = compute_osculating_paraboloid_second_derivatives(a)
n = compute_surface_normal(x_x, x_y)
I = compute_first_fundamental_form(x_x, x_y)
II = compute_second_fundamental_form(x_xx, x_xy, x_yy, n)
S = compute_shape_operator(I, II)
k_1,k_2, d_1, d_2 = compute_principal_curvatures(S, x_x, x_y)
d_1 = np.einsum('i,ij->ij', d_1[:,0], e1) +\
np.einsum('i,ij->ij', d_1[:,1], e2) +\
np.einsum('i,ij->ij', d_1[:,2], e3)
d_2 = np.einsum('i,ij->ij', d_2[:,0], e1) +\
np.einsum('i,ij->ij', d_2[:,1], e2) +\
np.einsum('i,ij->ij', d_2[:,2], e3)
return k_1, k_2, d_1, d_2

View File

@@ -0,0 +1,96 @@
import igl
import numpy as np
from scipy import sparse
from scipy.sparse import csr_matrix
import numpy.linalg as la
def vertex_tri_sum(data,F,V):
'''
Distributes data specified at each tetrahedron to the neighboring vertices.
All neighboring vertices will receive the value indicated at the corresponding tet position in data.
Input:
- data : array of shape (#t,)
Output:
- data_sum : array of shape (#v,), containing the summed data
'''
i = F.flatten('F') # (3*#f,)
j = np.arange(len(F)) # (#f,)
j = np.tile(j, 3) # (3*#f,)
if len(data) == len(F):
data = data[j]
m = sparse.coo_matrix((data, (i, j)), (len(V), len(F)))
return np.array(m.sum(axis=1)).flatten()
def compute_mass_matrix(V, F):
''' Assemble the Mass matrix by computing quantities per face.
Parameters:
- V : np.array (#v, 3)
- F : np.array (#f, 3)
Returns:
- M : scipy sparse diagonal matrix (#v, #v)
Mass matrix
'''
A = V[F[:,0],:]
B = V[F[:,1],:]
C = V[F[:,2],:]
v = la.norm(np.cross((B-A),(C-A),axis=1),axis=1)/6
M = sparse.diags(vertex_tri_sum(v,F,V) ,format='csr')
return M
def compute_cotangent(a, b, c, A):
''' Compute the cotangent of an angle in a triangle by using the triangle edge lengths and area only. The input parameters are defined in the handout figure. The purpose of this function is to check that your formula is correct. You should not directly use this in the `compute_laplacian_matrix` function.
Parameters:
- a : float
- b : float
- c : float
- A : float
'''
s_c = (2*A/(a*b))
c_c = np.sqrt(1-s_c**2)
return c_c/s_c
vi = [(0, 1, 2), (1, 2, 0), (2, 0, 1)]
def compute_laplacian_matrix(V, F):
''' Assemble the Laplacian matrix by computing quantities per face.
Parameters:
- V : np.array (#v, 3)
- F : np.array (#f, 3)
Returns:
- L : scipy sparse matrix (#v, #v)
Laplacian matrix
'''
sz = (3*2,F.shape[0])
W, I, J = np.zeros(sz), np.zeros(sz, np.int32),np.zeros(sz, np.int32)
Wc, Ic, Jc = 0,0,0
for v1, v2, v3 in vi:
vi1 = F[:,v1]
vi2 = F[:,v2]
vi3 = F[:,v3]
a, b = V[vi2] - V[vi1], V[vi3] - V[vi1]
cotan = np.sum(a*b,axis=1) / np.sqrt(np.sum(np.cross(a, b)**2, axis=-1))
W[Wc] = W[Wc+1] = cotan/2
I[Ic] = J[Jc+1] = vi2
J[Jc] = I[Ic+1] = vi3
Ic,Jc,Wc=Ic+2,Jc+2,Wc+2
I, J, W = I.flatten(), J.flatten(), W.flatten()
L = sparse.csr_matrix((W, (I, J)))
D = sparse.spdiags(L * np.ones(V.shape[0]), 0, V.shape[0], V.shape[0])
L -= D
return L

View File

@@ -0,0 +1,99 @@
import laplacian_utils
import scipy as sp
from scipy.sparse.linalg import spsolve
import igl
from utils import normalize_area, has_zero_area_triangle
import copy
import numpy as np
import numpy.linalg as la
class MCF():
def __init__(self, num_bdry_vx, num_intr_vx):
'''
Inputs:
- num_bdry_vx : int
The first num_bdry_vx vertices in v are boundary vertices in the mesh.
- num_intr_vx : int
The number of interior vertices in the mesh.
'''
self.num_bdry_vx = num_bdry_vx
self.num_intr_vx = num_intr_vx
self.L = None # Laplacian matrix.
self.M = None # Mass matrix.
self.average_mean_curvature = 0 # The average mean curvature value of the mesh.
def update_system(self, v, f):
'''
Update the member variables in the class, including the mass matrix, the Laplacian matrix, and the average mean curvature value of the mesh.
'''
self.M = laplacian_utils.compute_mass_matrix(v,f)
self.L = laplacian_utils.compute_laplacian_matrix(v,f)
# Update current average mean curvature.
Minv = sp.sparse.diags(1/self.M.diagonal())
hn = -0.5 * Minv.dot(self.L.dot(v))
H = np.linalg.norm(hn, axis=1)
H[:self.num_bdry_vx]*=0
self.average_mean_curvature = np.sum(H) / self.num_intr_vx / igl.bounding_box_diagonal(v)
def solve_laplace_equation(self, v, f):
'''
Solve the Laplace equation for the current mesh. Update the vertex positions with the solution.
'''
# Construct the LHS and RHS of the linear solve.
Lii = self.L[self.num_bdry_vx:, self.num_bdry_vx:]
Lib = self.L[self.num_bdry_vx:, :self.num_bdry_vx]
lhs = Lii
rhs = (-Lib).dot(v[:self.num_bdry_vx])
# # Solve linear system.
solution = spsolve(lhs, rhs)
# # Update the vertex positions using the solution of the linear solve.
# # v ...
v[self.num_bdry_vx:] = solution
def meet_stopping_criteria(self, mean_curvature_list, epsilon1, epsilon2):
'''
Stopping criteria for mean curvature flow.
'''
if (len(mean_curvature_list) < 2):
return False
# If the changes in the iteration is smaller than epsilon1, terminate the flow.
if (np.abs(mean_curvature_list[-1]-mean_curvature_list[-2]) < epsilon1):
print("Insufficient improvement from the previous iteration!")
return True
# If the average mean curvature value of the mesh is sufficiently small, terminate the flow.
if (np.abs(mean_curvature_list[-1]) < epsilon2):
print("Sufficiently small average mean curvature value!")
return True
return False
def run_mean_curvature_flow(self, v, f, max_iter, epsilon1, epsilon2):
'''
Running mean curvature flow by iteratively solving the Laplace equation.
'''
vs = [copy.deepcopy(v)]
average_mean_curvature_list = []
i = 0
self.update_system(v,f)
average_mean_curvature_list.append(self.average_mean_curvature)
print(i, has_zero_area_triangle(v, f),self.meet_stopping_criteria(average_mean_curvature_list, epsilon1, epsilon2))
while i < max_iter and not self.meet_stopping_criteria(average_mean_curvature_list, epsilon1, epsilon2):
'''
Your code here.
'''
self.solve_laplace_equation(v, f)
self.update_system(v, f)
if self.num_bdry_vx == 0:
normalize_area(v, f)
vs.append(copy.deepcopy(v))
average_mean_curvature_list.append(self.average_mean_curvature)
i += 1
return vs, average_mean_curvature_list

View File

@@ -0,0 +1,88 @@
import gmsh
import math
def remesh(filename, mesh_size):
# Import mesh
file = open(filename)
# Initialize gmsh
gmsh.initialize()
gmsh.model.add("remesher")
# The tags of the corresponding nodes:
nodes = []
# The x, y, z coordinates of all the nodes:
coords = []
# The connectivities of the triangle elements (3 node tags per triangle)
tris = []
# Tags
node_tag = 1
# Read file
for line in file.readlines():
data = [d.strip() for d in line.split(' ')]
# Generatae nodes
if(data[0]=="v"):
nodes.append(node_tag)
coords.extend([float(data[1]),float(data[2]),float(data[3])])
node_tag +=1
# Generate trinagular faces
if(data[0]=="f"):
# .obj from blender
if '//' in data[1]:
tris.extend([int([d.strip() for d in data[1].split('//')][0]),
int([d.strip() for d in data[2].split('//')][0]),
int([d.strip() for d in data[3].split('//')][0])])
# Add second triangle if quad face
if len(data) == 5:
tris.extend([int([d.strip() for d in data[3].split('//')][0]),
int([d.strip() for d in data[4].split('//')][0]),
int([d.strip() for d in data[1].split('//')][0])])
elif '/' in data[1]:
tris.extend([int([d.strip() for d in data[1].split('/')][0]),
int([d.strip() for d in data[2].split('/')][0]),
int([d.strip() for d in data[3].split('/')][0])])
# Add second triangle if quad face
if len(data) == 5:
tris.extend([int([d.strip() for d in data[3].split('/')][0]),
int([d.strip() for d in data[4].split('/')][0]),
int([d.strip() for d in data[1].split('/')][0])])
# .obj general
else:
tris.extend([int(data[1]),int(data[2]),int(data[3])])
# Add second triangle if quad face
if len(data) == 5:
tris.extend([int(data[3]),int(data[4]),int(data[1])])
model_tag = gmsh.model.addDiscreteEntity(2)
# Add all the nodes on the surface (for simplicity... see below):
gmsh.model.mesh.addNodes(2, model_tag, nodes, coords)
# Triangle elements: Type 2 for 3-node triangle elements:
gmsh.model.mesh.addElementsByType(model_tag, 2, [], tris)
# Create underlying surface for meshing
gmsh.model.mesh.classifySurfaces(math.pi, True, True, math.pi)
gmsh.model.mesh.createGeometry()
gmsh.model.geo.synchronize()
# Meshing parameters
gmsh.option.setNumber("Mesh.MeshSizeMin", mesh_size)
gmsh.option.setNumber("Mesh.MeshSizeMax", mesh_size)
# Generate mesh
gmsh.model.mesh.generate(2)
node_tags, node_coords, node_param = gmsh.model.mesh.getNodes()
element_tags, elements_node_tags = gmsh.model.mesh.getElementsByType(2)
# End gmsh
gmsh.finalize()
# Get new nodes and faces
v_remesh = node_coords.reshape((len(node_tags),3))
f_remesh= elements_node_tags.reshape((len(element_tags),3))-1
return v_remesh, f_remesh

View File

@@ -0,0 +1,423 @@
import numpy as np
# -----------------------------------------------------------------------------
# DERIVATIVES OF PARABOLOID
# -----------------------------------------------------------------------------
def compute_paraboloid_points(P, a, b, c, d, e):
"""Computes the points of the paraboloid x(u,v) = (u, v, z(u,v)) with
z(u,v) = a*u^2 + b*v^2 + c*u*v + d*u + e*v.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- a, b, c, d, e : float
The parameters of the paraboloid.
Returns:
- x : np.array (n, 3)
The points x(P), where the i-th row contains the (x,y,z) coordinates
of the point x(p_i)
"""
n = a*P[:,0]**2 + \
b*P[:,1]**2 + \
c*P[:,0]*P[:,1] + \
d*P[:,0] + \
e*P[:,1]
x = np.dstack((P[:,0],P[:,1],n))[0]
return x
def compute_paraboloid_first_derivatives(P, a, b, c, d, e):
"""Computes the first derivatives of the paraboloid x(u,v) = (u, v, z(u,v))
with z(u,v) = a*u^2 + b*v^2 + c*u*v + d*u + e*v.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- a, b, c, d, e : float
The parameters of the paraboloid.
Returns:
- x_u : np.array (n, 3)
The vectors x_u(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_u(p_i).
- x_v : np.array (n, 3)
The vectors x_v(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_v(p_i).
"""
nu = 2*a*P[:,0] + \
c*P[:,1] + \
d
nv = 2*b*P[:,1] + \
c*P[:,0] + \
e
z = np.zeros(P.shape[0])
o = np.ones(P.shape[0])
x_u = np.dstack((o,z,nu))[0]
x_v = np.dstack((z,o,nv))[0]
return x_u, x_v
def compute_paraboloid_second_derivatives(P, a, b, c, d, e):
"""Computes the second derivatives of the paraboloid x(u,v) = (u, v, z(u,v))
with z(u,v) = a*u^2 + b*v^2 + c*u*v + d*u + e*v.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- a, b, c, d, e : float
The parameters of the paraboloid.
Returns:
- x_uu : np.array (n, 3)
The vectors x_uu(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_uu(p_i).
- x_uv : np.array (n, 3)
The vectors x_uv(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_uv(p_i).
- x_vv : np.array (n, 3)
The vectors x_vv(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_vv(p_i).
"""
nuu = np.repeat(2*a, P.shape[0])
nuv = np.repeat( c, P.shape[0])
nvv = np.repeat(2*b, P.shape[0])
z = np.zeros(P.shape[0])
x_uu = np.dstack((z,z,nuu))[0]
x_uv = np.dstack((z,z,nuv))[0]
x_vv = np.dstack((z,z,nvv))[0]
return x_uu, x_uv, x_vv
# -----------------------------------------------------------------------------
# DERIVATIVES OF TORUS
# -----------------------------------------------------------------------------
def compute_torus_points(P, R, r):
"""Computes the second derivatives of a torus.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- R : float
The radius of revolution.
- r : float
The radius of the cross section.
Returns:
- x : np.array (n, 3)
The points x(P), where the i-th row contains the (x,y,z) coordinates
of the point x(p_i)
"""
cosu = np.cos(P[:,0])
sinu = np.sin(P[:,0])
cosv = np.cos(P[:,1])
sinv = np.sin(P[:,1])
fx = (r * cosu+ R) * cosv
fy = (r * cosu+ R) * sinv
fz = r * sinu
x = np.dstack((fx, fy, fz))[0]
return x
def compute_torus_first_derivatives(P, R, r):
"""Computes the second derivatives of a torus.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- R : float
The radius of revolution.
- r : float
The radius of the cross section.
Returns:
- x_u : np.array (n, 3)
The vectors x_u(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_u(p_i).
- x_v : np.array (n, 3)
The vectors x_v(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_v(p_i).
"""
cosu = np.cos(P[:,0])
sinu = np.sin(P[:,0])
cosv = np.cos(P[:,1])
sinv = np.sin(P[:,1])
z = np.zeros(P.shape[0])
fx_u = - r * sinu * cosv
fy_u = - r * sinu * sinv
fz_u = r * cosu
fx_v = -(r * cosu+ R) * sinv
fy_v = (r * cosu+ R) * cosv
fz_v = z
x_u = np.dstack((fx_u, fy_u, fz_u))[0]
x_v = np.dstack((fx_v, fy_v, fz_v))[0]
return x_u, x_v
def compute_torus_second_derivatives(P, R, r):
"""Computes the second derivatives of a torus.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- R : float
The radius of revolution.
- r : float
The radius of the cross section.
Returns:
- x_uu : np.array (n, 3)
The vectors x_uu(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_uu(p_i).
- x_uv : np.array (n, 3)
The vectors x_uv(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_uv(p_i).
- x_vv : np.array (n, 3)
The vectors x_vv(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_vv(p_i).
"""
cosu = np.cos(P[:,0])
sinu = np.sin(P[:,0])
cosv = np.cos(P[:,1])
sinv = np.sin(P[:,1])
z = np.zeros(P.shape[0])
fx_uu = - r * cosu * cosv
fy_uu = - r * cosu * sinv
fz_uu = - r * sinu
fx_uv = (r * sinu) * sinv
fy_uv = -(r * sinu) * cosv
fz_uv = z
fx_vv = -(r * cosu+ R) * cosv
fy_vv = -(r * cosu+ R) * sinv
fz_vv = z
x_uu = np.dstack((fx_uu, fy_uu, fz_uu))[0]
x_uv = np.dstack((fx_uv, fy_uv, fz_uv))[0]
x_vv = np.dstack((fx_vv, fy_vv, fz_vv))[0]
return x_uu, x_uv, x_vv
# -----------------------------------------------------------------------------
# SHAPE OPERATOR
# -----------------------------------------------------------------------------
def compute_first_fundamental_form(x_u, x_v):
"""Computes the first fundamental form I.
Try to vectorize this function.
Parameters:
- x_u : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_u(p_i).
- x_v : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_v(p_i).
Returns:
- I : np.array (n, 2, 2)
The first fundamental forms.
The (i, j, k) position contains the (j, k) element of the first
fundamental form I(p_i).
"""
e00 = np.einsum('lm,ml->m',x_u.T,x_u)
e01 = np.einsum('lm,ml->m',x_u.T,x_v)
e10 = np.einsum('lm,ml->m',x_v.T,x_u)
e11 = np.einsum('lm,ml->m',x_v.T,x_v)
I = np.dstack((e00,e01,e10,e11))[0].reshape((x_u.shape[0],2,2))
return I
def compute_surface_normal(x_u, x_v):
"""Computes the surface normal n.
Try to vectorize this function.
Parameters:
- x_u : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_u(p_i).
- x_v : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_v(p_i).
Returns:
- n : np.array (n, 3)
The surface normals.
The i-th row contains the (x,y,z) coordinates of the vector n(p_i).
"""
exp = np.cross(x_u, x_v)
div = np.linalg.norm(exp, axis=1)
n = exp/div[:,None]
return n
def compute_second_fundamental_form(x_uu, x_uv, x_vv, n):
"""Computes the second fundamental form II.
Try to vectorize this function.
Parameters:
- x_uu : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_uu(p_i).
- x_uv : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_uv(p_i).
- x_vv : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_vv(p_i).
- n : np.array (n, 3)
The surface normals.
The i-th row contains the (x,y,z) coordinates of the vector n(p_i).
Returns:
- II : np.array (n, 2, 2)
The second fundamental forms.
The (i, j, k) position contains the (j, k) element of the second
fundamental form II(p_i).
"""
e00 = np.einsum('lm,ml->m',n.T, x_uu)
e01 = np.einsum('lm,ml->m',n.T, x_uv)
e10 = np.einsum('lm,ml->m',n.T, x_uv)
e11 = np.einsum('lm,ml->m',n.T, x_vv)
II = np.dstack((e00,e01,e10,e11))[0].reshape((n.shape[0],2,2))
return II
def compute_shape_operator(I, II):
"""Computes the shape operator S.
Try to vectorize this function.
Parameters:
- I : np.array (n, 2, 2)
The first fundamental forms.
The (i, j, k) position contains the (j, k) element of the first
fundamental form I(p_i).
- II : np.array (n, 2, 2)
The second fundamental forms.
The (i, j, k) position contains the (j, k) element of the second
fundamental form II(p_i).
Returns:
- S : np.array (n, 2, 2)
The shape operators.
The (i, j, k) position contains the (j, k) element of the shape
operator S(p_i).
"""
Iinv = np.linalg.inv(I)
S = Iinv @ II
return S
# -----------------------------------------------------------------------------
# PRINCIPAL CURVATURES
# -----------------------------------------------------------------------------
def compute_principal_curvatures(S, x_u, x_v):
"""Computes principal curvatures and corresponding principal directions.
Try to vectorize this function.
Parameters:
- S : np.array (n, 2, 2)
The shape operators.
The (i, j, k) position contains the (j, k) element of the shape
operator S(p_i).
- x_u : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_u(p_i).
- x_v : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_v(p_i).
Returns:
- k_1 : np.array (n)
The min principal curvature. i-th element contains the curvature k_1(p_i).
- k_2 : np.array (n)
The max principal curvature. i-th element contains the curvature k_2(p_i).
- e_1 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_1.
The i-th row contains the (x,y,z) coordinates of e_1(p_i).
- e_2 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_2.
The i-th row contains the (x,y,z) coordinates of e_2(p_i).
"""
# this section computes the ordered eigenvalues and eigenvectors of S where
# k_1[i] = min eigenvalue at p_i, k_2[i] = max eigenvalue at p_i,
# bar_e_1[i] = [u, v] components of the eigenvector of k_1,
# bar_e_2[i] = [u, v] components of the eigenvector of k_2
eig = np.linalg.eig(S)
index = np.argsort(eig[0], axis=1)
k_1 = eig[0][np.arange(len(S)), index[:, 0]]
k_2 = eig[0][np.arange(len(S)), index[:, 1]]
bar_e_1 = eig[1][np.arange(len(S)), :, index[:, 0]]
bar_e_2 = eig[1][np.arange(len(S)), :, index[:, 1]]
# Compute the normalized 3D vectors e_1, e_2
J = np.concatenate((x_u,x_v), axis=1).reshape((S.shape[0],2,3))
Je1 = np.einsum('lnm,ln->lm',J, bar_e_1)
Je2 = np.einsum('lnm,ln->lm',J, bar_e_2)
e_1 = Je1/np.linalg.norm(Je1, axis=1)[:,None]
e_2 = Je2/np.linalg.norm(Je2, axis=1)[:,None]
return k_1, k_2, e_1, e_2
# -----------------------------------------------------------------------------
# ASYMPTOTIC DIRECTIONS
# -----------------------------------------------------------------------------
def compute_asymptotic_directions(k_1, k_2, e_1, e_2):
"""Computes principal curvatures and corresponding principal directions.
Try to vectorize this function.
Parameters:
- k_1 : np.array (n)
The min principal curvature. i-th element contains the curvature k_1(p_i).
- k_2 : np.array (n)
The max principal curvature. i-th element contains the curvature k_2(p_i).
- e_1 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_1.
The i-th row contains the (x,y,z) coordinates of e_1(p_i).
- e_2 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_2.
The i-th row contains the (x,y,z) coordinates of e_2(p_i).
Returns:
- a_1 : np.array (n, 3)
The first unitized asymptotic direction. The i-th row contains the
(x,y,z) coordinates of a_2(p_i) if it exists, (0, 0, 0) otherwise.
- a_2 : np.array (n, 3)
The second unitized asymptotic direction. The i-th row contains the
(x,y,z) coordinates of a_2(p_i) if it exists, (0, 0, 0) otherwise.
"""
a_1 = np.zeros((k_1.shape[0],3))
a_2 = np.zeros((k_1.shape[0],3))
k1k2 = k_1*k_2
v1 = np.where(k1k2<=0)
v2 = np.where(k1k2<0)
f = np.zeros((k_1.shape[0]))
ff = np.zeros((k_1.shape[0]))
v3 = np.where((k_1-k_2)!=0)
f[v3] = (k_1[v3]/((k_1 - k_2)[v3]))
ff[v1] = f[v1]
cosT = np.sqrt(1-f)
sinT = np.sqrt(f)
a_1[v1] =(e_1*cosT[:,None] + e_2*sinT[:,None])[v1]
a_2[v2] =(e_1*cosT[:,None] - e_2*sinT[:,None])[v2]
return a_1, a_2

View File

@@ -0,0 +1,73 @@
import igl
import numpy as np
import remesher_helper
from matplotlib import cm
import meshplot as mp
cmap = cm.get_cmap('PiYG')
def normalize_area(v, f):
cm = np.mean(v, axis=0)
v -= cm
v /= (np.sum(igl.doublearea(v, f))/2)**0.5
v += cm
def has_zero_area_triangle(v, f):
if np.min(igl.doublearea(v, f))/2 < 1e-10:
return True
return False
def reorder_mesh(raw_v, raw_f):
np.random.shuffle(raw_f)
bdry_vx_idx = np.array(list(set((igl.boundary_facets(raw_f)).flatten())))
num_bdry_vx = len(bdry_vx_idx)
num_intr_vx = len(raw_v) - num_bdry_vx
reorder_vx_map = {}
map_to_original = {}
boundary_vertices = []
interior_vertices = []
for i in range(len(raw_v)):
if i in bdry_vx_idx:
reorder_vx_map[i] = len(boundary_vertices)
map_to_original[len(boundary_vertices)] = i
boundary_vertices.append(i)
else:
reorder_vx_map[i] = len(interior_vertices) + num_bdry_vx
map_to_original[len(interior_vertices) + num_bdry_vx] = i
interior_vertices.append(i)
v = np.array([raw_v[map_to_original[i]] for i in range(len(raw_v))])
f = np.array([[reorder_vx_map[i] for i in face] for face in raw_f])
return v, f, num_bdry_vx, num_intr_vx
def parse_input_mesh(name):
raw_v, raw_f = igl.read_triangle_mesh(name)
v, f, num_bdry_vx, num_intr_vx = reorder_mesh(raw_v, raw_f)
# normalize_area(v, f)
return v, f, num_bdry_vx, num_intr_vx
def remesh(input_name, output_name, mesh_size = 0.03):
vr, fr = remesher_helper.remesh(input_name, mesh_size)
igl.write_obj(output_name, vr, fr.astype('int64'))
def get_diverging_colors(values, percentile = 95):
max_val = np.percentile(np.abs(values), percentile)
return(cmap(values / max_val * 0.5 * -1 + 0.5)[:, :3])
def plot_directions(x, F, d_1, d_2, scale=0.1):
color = np.ones((len(x), 3))
shading_options = {
"flat": False,
"wireframe":False,
"metalness": 0.05,
}
p = mp.plot(x, F, c=color, shading=shading_options)
p.add_lines(x+d_1*scale, x-d_1*scale, shading={"line_color": "red"})
p.add_lines(x+d_2*scale, x-d_2*scale, shading={"line_color": "blue"})
p.update_object()

View File

@@ -0,0 +1,155 @@
import time
import pytest
import json
import sys
import igl
import numpy as np
sys.path.append('../')
sys.path.append('../src')
import utils, laplacian_utils, mean_curvature_flow, remesher_helper
from utils import parse_input_mesh, normalize_area, get_diverging_colors, remesh
from mean_curvature_flow import MCF
import copy
import numpy.linalg as la
import fitting
epsilon1 = 5e-2
epsilon2 = 1e-3
eps = 1E-6
with open('test_data.json', 'r') as infile:
homework_data = json.load(infile)
v = np.array(homework_data[0], dtype=float)
f = np.array(homework_data[1], dtype=int)
num_bdry_vx, num_intr_vx = int(homework_data[2]), int(homework_data[3])
curr_mcf = MCF(num_bdry_vx, num_intr_vx)
curr_mcf.bbox_diagonal = igl.bounding_box_diagonal(v)
@pytest.mark.timeout(0.5)
def test_mass_matrix():
student_mass_matrix = laplacian_utils.compute_mass_matrix(v, f).toarray()
assert np.linalg.norm(student_mass_matrix - np.array(homework_data[4], dtype=float)) < eps
@pytest.mark.timeout(0.5)
def test_cotan():
cotan, a, b, c, A = homework_data[5]
student_cotan = laplacian_utils.compute_cotangent(a, b, c, A)
assert np.linalg.norm(student_cotan - cotan) < eps
@pytest.mark.timeout(0.5)
def test_laplacian_matrix():
student_laplacian_matrix = laplacian_utils.compute_laplacian_matrix(v, f).toarray()
assert np.linalg.norm(student_laplacian_matrix - np.array(homework_data[6], dtype=float)) < eps
@pytest.mark.timeout(0.5)
def test_average_mean_curvature():
data = homework_data[7]
laplace_v = copy.deepcopy(v)
curr_mcf.update_system(laplace_v, f)
assert np.linalg.norm(curr_mcf.average_mean_curvature - data) < eps
@pytest.mark.timeout(0.5)
def test_laplace_solution():
data = homework_data[8]
laplace_v = copy.deepcopy(v)
curr_mcf.solve_laplace_equation(laplace_v, f)
assert np.linalg.norm(laplace_v - np.array(data, dtype=float)) < eps
@pytest.mark.timeout(0.5)
def test_meet_sc():
data = homework_data[9]
student_sc = [curr_mcf.meet_stopping_criteria([0.001, 0.001], epsilon1, epsilon2), curr_mcf.meet_stopping_criteria([1, 0.5], epsilon1, epsilon2)]
assert student_sc == data
@pytest.mark.timeout(0.5)
def test_mean_curvature_flow():
data = np.array(homework_data[10], dtype=float)
_, student_mean_curvature_flow = curr_mcf.run_mean_curvature_flow(v, f, 100, epsilon1, epsilon2)
assert np.linalg.norm(student_mean_curvature_flow - data) < eps
@pytest.mark.timeout(0.5)
def test_average_mean_curvature():
data = homework_data[7]
laplace_v = copy.deepcopy(v)
curr_mcf.update_system(laplace_v, f)
assert np.linalg.norm(curr_mcf.average_mean_curvature - data) < eps
@pytest.mark.timeout(0.5)
def test_laplace_solution():
data = homework_data[8]
laplace_v = copy.deepcopy(v)
curr_mcf.solve_laplace_equation(laplace_v, f)
assert np.linalg.norm(laplace_v - np.array(data, dtype=float)) < eps
@pytest.mark.timeout(0.5)
def test_meet_sc():
data = homework_data[9]
student_sc = [curr_mcf.meet_stopping_criteria([0.001, 0.001], epsilon1, epsilon2), curr_mcf.meet_stopping_criteria([1, 0.5], epsilon1, epsilon2)]
assert student_sc == data
@pytest.mark.timeout(0.5)
def test_mean_curvature_flow():
data = np.array(homework_data[10], dtype=float)
_, student_mean_curvature_flow = curr_mcf.run_mean_curvature_flow(v, f, 100, epsilon1, epsilon2)
assert np.linalg.norm(student_mean_curvature_flow - data) < eps
fitting_v = np.array(homework_data[11], dtype=float)
fitting_f = np.array(homework_data[12], dtype=int)
@pytest.mark.timeout(0.5)
def test_osculating_paraboloids():
[paraboloids_parameters, e1, e2, e3] = homework_data[13]
paraboloids_parameters = np.array(paraboloids_parameters)
e1 = np.array(e1)
e2 = np.array(e2)
e3 = np.array(e3)
student_paraboloids_parameters = fitting.compute_osculating_paraboloids(fitting_v, fitting_f, e1, e2, e3)
assert np.linalg.norm(student_paraboloids_parameters - paraboloids_parameters) < eps
@pytest.mark.timeout(0.5)
def test_osculating_paraboloid_first_derivatives():
[op_fd_x, op_fd_y, paraboloids_parameters] = homework_data[14]
op_fd_x = np.array(op_fd_x)
op_fd_y = np.array(op_fd_y)
paraboloids_parameters = np.array(paraboloids_parameters)
student_fd_x, student_fd_y = fitting.compute_osculating_paraboloid_first_derivatives(paraboloids_parameters)
assert np.linalg.norm(student_fd_x - op_fd_x) < eps
assert np.linalg.norm(student_fd_y - op_fd_y) < eps
@pytest.mark.timeout(0.5)
def test_osculating_paraboloid_second_derivatives():
[op_sd_xx, op_sd_xy, op_sd_yy, paraboloids_parameters] = homework_data[15]
op_sd_xx = np.array(op_sd_xx)
op_sd_xy = np.array(op_sd_xy)
op_sd_yy = np.array(op_sd_yy)
paraboloids_parameters = np.array(paraboloids_parameters)
student_sd_xx, student_sd_xy, student_sd_yy = fitting.compute_osculating_paraboloid_second_derivatives(paraboloids_parameters)
assert np.linalg.norm(student_sd_xx - op_sd_xx) < eps
assert np.linalg.norm(student_sd_xy - op_sd_xy) < eps
assert np.linalg.norm(student_sd_yy - op_sd_yy) < eps
@pytest.mark.timeout(0.5)
def test_mesh_principal_curvatures():
k1, k2, d1, d2 = homework_data[16]
k1 = np.array(k1)
k2 = np.array(k2)
d1 = np.array(d1)
d2 = np.array(d2)
student_k1, student_k2, student_d1, student_d2 = fitting.compute_mesh_principal_curvatures(fitting_v, fitting_f)
assert np.linalg.norm(k1 - student_k1) < eps
assert np.linalg.norm(k2 - student_k2) < eps
assert np.linalg.norm(d1 - student_d1) < eps
assert np.linalg.norm(d2 - student_d2) < eps

File diff suppressed because one or more lines are too long