Disabled external gits
This commit is contained in:
27029
cs457-gc/assignment_3_2/data/bob_tri.obj
Normal file
27029
cs457-gc/assignment_3_2/data/bob_tri.obj
Normal file
File diff suppressed because it is too large
Load Diff
70742
cs457-gc/assignment_3_2/data/cube_remesh.obj
Normal file
70742
cs457-gc/assignment_3_2/data/cube_remesh.obj
Normal file
File diff suppressed because it is too large
Load Diff
35898
cs457-gc/assignment_3_2/data/final.obj
Normal file
35898
cs457-gc/assignment_3_2/data/final.obj
Normal file
File diff suppressed because it is too large
Load Diff
47351
cs457-gc/assignment_3_2/data/half_cube_remesh.obj
Normal file
47351
cs457-gc/assignment_3_2/data/half_cube_remesh.obj
Normal file
File diff suppressed because it is too large
Load Diff
7765
cs457-gc/assignment_3_2/data/mesh.obj
Normal file
7765
cs457-gc/assignment_3_2/data/mesh.obj
Normal file
File diff suppressed because it is too large
Load Diff
35898
cs457-gc/assignment_3_2/data/remesh.obj
Normal file
35898
cs457-gc/assignment_3_2/data/remesh.obj
Normal file
File diff suppressed because it is too large
Load Diff
33624
cs457-gc/assignment_3_2/data/two_rings_remesh.obj
Normal file
33624
cs457-gc/assignment_3_2/data/two_rings_remesh.obj
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
375
cs457-gc/assignment_3_2/notebook/fitting.ipynb
Normal file
375
cs457-gc/assignment_3_2/notebook/fitting.ipynb
Normal 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
|
||||
}
|
749
cs457-gc/assignment_3_2/notebook/mean_curvature_flow.ipynb
Normal file
749
cs457-gc/assignment_3_2/notebook/mean_curvature_flow.ipynb
Normal file
File diff suppressed because one or more lines are too long
221
cs457-gc/assignment_3_2/src/fitting.py
Normal file
221
cs457-gc/assignment_3_2/src/fitting.py
Normal 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
|
96
cs457-gc/assignment_3_2/src/laplacian_utils.py
Normal file
96
cs457-gc/assignment_3_2/src/laplacian_utils.py
Normal 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
|
99
cs457-gc/assignment_3_2/src/mean_curvature_flow.py
Normal file
99
cs457-gc/assignment_3_2/src/mean_curvature_flow.py
Normal 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
|
88
cs457-gc/assignment_3_2/src/remesher_helper.py
Normal file
88
cs457-gc/assignment_3_2/src/remesher_helper.py
Normal 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
|
423
cs457-gc/assignment_3_2/src/smooth_surfaces.py
Normal file
423
cs457-gc/assignment_3_2/src/smooth_surfaces.py
Normal 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
|
||||
|
73
cs457-gc/assignment_3_2/src/utils.py
Normal file
73
cs457-gc/assignment_3_2/src/utils.py
Normal 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()
|
155
cs457-gc/assignment_3_2/test/test.py
Normal file
155
cs457-gc/assignment_3_2/test/test.py
Normal 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
|
1
cs457-gc/assignment_3_2/test/test_data.json
Normal file
1
cs457-gc/assignment_3_2/test/test_data.json
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user