Disabled external gits
1
cs457-gc
31
cs457-gc/.github/workflows/autograder.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: Assignment 3 Autograder
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
grading:
|
||||
name: Grading
|
||||
runs-on: "macos-11"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache conda
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
# Increase this value to reset cache if environment.yml has not changed
|
||||
CACHE_NUMBER: 0
|
||||
with:
|
||||
path: ~/conda_pkgs_dir
|
||||
key:
|
||||
${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{
|
||||
hashFiles('environment.yml') }}
|
||||
- uses: conda-incubator/setup-miniconda@v2
|
||||
with:
|
||||
activate-environment: gc_course_env
|
||||
channel-priority: strict
|
||||
environment-file: environment.yml
|
||||
use-only-tar-bz2: true # IMPORTANT: This needs to be set for caching to work properly!
|
||||
auto-activate-base: false
|
||||
- name: Run tests
|
||||
working-directory: ${{github.workspace}}/assignment_3_3/test
|
||||
shell: bash -l {0}
|
||||
run: pytest test.py
|
1
cs457-gc/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
__pycache__/
|
24
cs457-gc/Dockerfile
Normal file
@@ -0,0 +1,24 @@
|
||||
FROM archlinux:latest
|
||||
|
||||
# Link in our build files to the docker image
|
||||
COPY environment.yml /
|
||||
|
||||
#EXPORT DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Run all ubuntu updates and apt-get installs
|
||||
RUN pacman -Syu --noconfirm base-devel jupyter python wget bzip2 opencv glu libxinerama
|
||||
|
||||
RUN wget -O /tmp/Anaconda3.sh https://repo.anaconda.com/archive/Anaconda3-2021.05-Linux-x86_64.sh &&\
|
||||
chmod +x /tmp/Anaconda3.sh
|
||||
|
||||
RUN /tmp/Anaconda3.sh -b -p /opt/conda
|
||||
ENV PATH="/opt/conda/bin:${PATH}"
|
||||
|
||||
#ENV PY3PATH=/opt/conda/anaconda3/bin
|
||||
|
||||
RUN conda install jupyter -y --quiet
|
||||
RUN conda init bash
|
||||
RUN conda env update --file /environment.yml --prune
|
||||
RUN python -m ipykernel install --user --name=gc_course_env
|
||||
|
||||
ENTRYPOINT ["conda", "run", "--no-capture-output", "-n", "gc_course_env", "jupyter-notebook", "--notebook-dir=/opt/notebooks", "--ip='*'","--port=8888","--no-browser","--allow-root"]
|
5
cs457-gc/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
CS 457 Geometric Computing — Assignments
|
||||
======================================
|
||||
|
||||
## Build status
|
||||
[](https://github.com/EPFL-GC/cs457-2021-choelzl/actions/workflows/autograder.yml)
|
1
cs457-gc/assignment_1_1/data/dance.json
Normal file
1
cs457-gc/assignment_1_1/data/dinosaur.json
Normal file
1
cs457-gc/assignment_1_1/data/fans.json
Normal file
@@ -0,0 +1 @@
|
||||
[[[0.2, 0.0, 0], [0.5270624654048792, 0.09293533316960212, 0], [0.11285295279178453, 0.04107511566525849, 0], [0.537347324533129, 0.3102376224675271, 0], [0.5376274099831806, 0.4511229614276831, 0], [0.3475414767429655, 0.41418380348392614, 0], [0.5632041314409677, 0.975498170688456, 0], [0.13777413649311007, 0.37853132899967884, 0], [0.15821749037280028, 0.8972959766968018, 0], [3.3663921360634227e-17, 0.5497735573076639, 0], [-0.25677616861861896, 1.4562500167978654, 0], [-0.45300365061759007, 1.2446173010023398, 0], [-0.4963687859959057, 0.8597359566361923, 0], [-0.7100275174261769, 0.8461778447333945, 0], [-0.6706959498524094, 0.5627807241532525, 0], [-0.9912140281389583, 0.5722776859705607, 0], [-1.1871787691243278, 0.4320977347140436, 0], [-1.6954303253313614, 0.29895011026725005, 0], [-0.2, 2.4492935982947065e-17, 0], [0, 0, 0]], [[19, 0, 1], [19, 1, 2], [19, 2, 3], [19, 3, 4], [19, 4, 5], [19, 5, 6], [19, 6, 7], [19, 7, 8], [19, 8, 9], [19, 9, 10], [19, 10, 11], [19, 11, 12], [19, 12, 13], [19, 13, 14], [19, 14, 15], [19, 15, 16], [19, 16, 17], [19, 17, 18]]]
|
1
cs457-gc/assignment_1_1/data/gym.json
Normal file
@@ -0,0 +1,311 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import meshplot as mp\n",
|
||||
"import numpy as np\n",
|
||||
"import sys\n",
|
||||
"import json\n",
|
||||
"from matplotlib import pyplot as plt\n",
|
||||
"sys.path.append(\"../src/\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 1. Load OBJ model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with open('../data/gym.json', 'r') as infile:\n",
|
||||
" [V, F] = json.load(infile)\n",
|
||||
" V = np.array(V)\n",
|
||||
" F = np.array(F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 2. Mesh Plotting"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def draw_mesh(V, F):\n",
|
||||
" shading = {\"flat\":True, # Flat or smooth shading of triangles\n",
|
||||
" \"wireframe\":True, \"wire_width\": 0.03, \"wire_color\": \"black\", # Wireframe rendering\n",
|
||||
" \"width\": 600, \"height\": 600, # Size of the viewer canvas\n",
|
||||
" \"antialias\": True, # Antialising, might not work on all GPUs\n",
|
||||
" \"scale\": 2.0, # Scaling of the model\n",
|
||||
" \"side\": \"DoubleSide\", # FrontSide, BackSide or DoubleSide rendering of the triangles\n",
|
||||
" \"colormap\": \"viridis\", \"normalize\": [None, None], # Colormap and normalization for colors\n",
|
||||
" \"background\": \"#ffffff\", # Background color of the canvas\n",
|
||||
" \"line_width\": 1.0, \"line_color\": \"black\", # Line properties of overlay lines\n",
|
||||
" \"bbox\": False, # Enable plotting of bounding box\n",
|
||||
" \"point_color\": \"red\", \"point_size\": 0.01 # Point properties of overlay points\n",
|
||||
" }\n",
|
||||
" #p = mp.plot(V, F, shading=shading, return_plot=True)\n",
|
||||
" mp.plot(V, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/home/sora/.local/lib/python3.9/site-packages/jupyter_client/session.py:716: UserWarning: Message serialization failed with:\n",
|
||||
"Out of range float values are not JSON compliant\n",
|
||||
"Supporting this message is deprecated in jupyter-client 7, please make sure your message is JSON-compliant\n",
|
||||
" content = self.pack(content)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "c463e93a5b0044fbba0746c52a887176",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.5660395…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"draw_mesh(V, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 3. Mesh Centroid Plotting"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from geometry import compute_mesh_centroid\n",
|
||||
"def draw_mesh_with_centroid(V, F):\n",
|
||||
" shading = {\"flat\":True, # Flat or smooth shading of triangles\n",
|
||||
" \"wireframe\":True, \"wire_width\": 0.03, \"wire_color\": \"black\", # Wireframe rendering\n",
|
||||
" \"width\": 600, \"height\": 600, # Size of the viewer canvas\n",
|
||||
" \"antialias\": True, # Antialising, might not work on all GPUs\n",
|
||||
" \"scale\": 2.0, # Scaling of the model\n",
|
||||
" \"side\": \"DoubleSide\", # FrontSide, BackSide or DoubleSide rendering of the triangles\n",
|
||||
" \"colormap\": \"viridis\", \"normalize\": [None, None], # Colormap and normalization for colors\n",
|
||||
" \"background\": \"#ffffff\", # Background color of the canvas\n",
|
||||
" \"line_width\": 1.0, \"line_color\": \"black\", # Line properties of overlay lines\n",
|
||||
" \"bbox\": False, # Enable plotting of bounding box\n",
|
||||
" \"point_color\": \"red\", \"point_size\": 0.01 # Point properties of overlay points\n",
|
||||
" }\n",
|
||||
" mesh_plot = mp.plot(V, F, shading=shading, return_plot=True)\n",
|
||||
" center0 = np.array(compute_mesh_centroid(V, F))\n",
|
||||
" center1 = center0.copy()\n",
|
||||
" center1[1] = 0\n",
|
||||
" vertices = np.vstack([center0, center1])\n",
|
||||
" mesh_plot.add_points(vertices, shading={\"point_color\": \"black\", \"point_size\": 0.1})\n",
|
||||
" mesh_plot.add_edges(vertices, np.array([[0, 1]]), shading={\"line_color\": \"black\", \"line_width\" : 0.5});"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "4f0181b991864ebe91e419ff21dbb932",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.5660395…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[0.70220297 0.14449098 0. ]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"draw_mesh_with_centroid(V, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 4. Shearing Transformation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ipywidgets import interact, interactive, fixed, interact_manual\n",
|
||||
"import ipywidgets as widgets\n",
|
||||
"from shear import shear_transformation\n",
|
||||
"def draw_mesh_after_shear_transformation(V, F, nu):\n",
|
||||
" V1 = shear_transformation(V, nu)\n",
|
||||
" draw_mesh_with_centroid(V1, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "29b3847a9adc46aab07c80e2d794a69c",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"interactive(children=(FloatSlider(value=0.0, description='nu', max=1.0, min=-1.0), Output()), _dom_classes=('w…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"interact(draw_mesh_after_shear_transformation, V = fixed(V), F = fixed(F), nu = (-1, 1, 0.1));"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 5. Shear Equilibrium"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from shear import shear_equilibrium\n",
|
||||
"from geometry import compute_center_support_line\n",
|
||||
"def compute_equilibrium_mesh(V, F):\n",
|
||||
" x_csl = compute_center_support_line(V)\n",
|
||||
" V1 = shear_equilibrium(V, F, x_csl)\n",
|
||||
" draw_mesh_with_centroid(V1, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Copy the following codes and find equilibrium shapes for all other examples in ../data folder "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "1a828dcd3277486da42e79e5865c4917",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.5046897…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[0.63531671 0.39031879 0. ]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"with open('../data/dinosaur.json', 'r') as infile:\n",
|
||||
" [V, F] = json.load(infile)\n",
|
||||
" V = np.array(V)\n",
|
||||
" F = np.array(F)\n",
|
||||
" compute_equilibrium_mesh(V, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "gc_course_env",
|
||||
"language": "python",
|
||||
"name": "gc_course_env"
|
||||
},
|
||||
"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": 4
|
||||
}
|
374
cs457-gc/assignment_1_1/notebook/make_it_stand_nb1.ipynb
Normal file
@@ -0,0 +1,374 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import meshplot as mp\n",
|
||||
"import numpy as np\n",
|
||||
"import sys\n",
|
||||
"import json\n",
|
||||
"from matplotlib import pyplot as plt\n",
|
||||
"sys.path.append(\"../src/\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 1. Load OBJ model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with open('../data/gym.json', 'r') as infile:\n",
|
||||
" [V, F] = json.load(infile)\n",
|
||||
" V = np.array(V)\n",
|
||||
" F = np.array(F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 2. Mesh Plotting"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def draw_mesh(V, F):\n",
|
||||
" shading = {\"flat\":True, # Flat or smooth shading of triangles\n",
|
||||
" \"wireframe\":True, \"wire_width\": 0.03, \"wire_color\": \"black\", # Wireframe rendering\n",
|
||||
" \"width\": 600, \"height\": 600, # Size of the viewer canvas\n",
|
||||
" \"antialias\": True, # Antialising, might not work on all GPUs\n",
|
||||
" \"scale\": 2.0, # Scaling of the model\n",
|
||||
" \"side\": \"DoubleSide\", # FrontSide, BackSide or DoubleSide rendering of the triangles\n",
|
||||
" \"colormap\": \"viridis\", \"normalize\": [None, None], # Colormap and normalization for colors\n",
|
||||
" \"background\": \"#ffffff\", # Background color of the canvas\n",
|
||||
" \"line_width\": 1.0, \"line_color\": \"black\", # Line properties of overlay lines\n",
|
||||
" \"bbox\": False, # Enable plotting of bounding box\n",
|
||||
" \"point_color\": \"red\", \"point_size\": 0.01 # Point properties of overlay points\n",
|
||||
" }\n",
|
||||
" #p = mp.plot(V, F, shading=shading, return_plot=True)\n",
|
||||
" mp.plot(V, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/home/sora/.local/lib/python3.9/site-packages/jupyter_client/session.py:716: UserWarning: Message serialization failed with:\n",
|
||||
"Out of range float values are not JSON compliant\n",
|
||||
"Supporting this message is deprecated in jupyter-client 7, please make sure your message is JSON-compliant\n",
|
||||
" content = self.pack(content)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "10f6965f0b774229b05913c93cc79731",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.5660395…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"draw_mesh(V, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 3. Mesh Centroid Plotting"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from geometry import compute_mesh_centroid\n",
|
||||
"def draw_mesh_with_centroid(V, F):\n",
|
||||
" shading = {\"flat\":True, # Flat or smooth shading of triangles\n",
|
||||
" \"wireframe\":True, \"wire_width\": 0.03, \"wire_color\": \"black\", # Wireframe rendering\n",
|
||||
" \"width\": 600, \"height\": 600, # Size of the viewer canvas\n",
|
||||
" \"antialias\": True, # Antialising, might not work on all GPUs\n",
|
||||
" \"scale\": 2.0, # Scaling of the model\n",
|
||||
" \"side\": \"DoubleSide\", # FrontSide, BackSide or DoubleSide rendering of the triangles\n",
|
||||
" \"colormap\": \"viridis\", \"normalize\": [None, None], # Colormap and normalization for colors\n",
|
||||
" \"background\": \"#ffffff\", # Background color of the canvas\n",
|
||||
" \"line_width\": 1.0, \"line_color\": \"black\", # Line properties of overlay lines\n",
|
||||
" \"bbox\": False, # Enable plotting of bounding box\n",
|
||||
" \"point_color\": \"red\", \"point_size\": 0.01 # Point properties of overlay points\n",
|
||||
" }\n",
|
||||
" mesh_plot = mp.plot(V, F, shading=shading, return_plot=True)\n",
|
||||
" center0 = np.array(compute_mesh_centroid(V, F))\n",
|
||||
" center1 = center0.copy()\n",
|
||||
" center1[1] = 0\n",
|
||||
" vertices = np.vstack([center0, center1])\n",
|
||||
" mesh_plot.add_points(vertices, shading={\"point_color\": \"black\", \"point_size\": 0.1})\n",
|
||||
" mesh_plot.add_edges(vertices, np.array([[0, 1]]), shading={\"line_color\": \"black\", \"line_width\" : 0.5});"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "183e46c464694a4faf5cd2c46de6f0b3",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.5660395…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"draw_mesh_with_centroid(V, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 4. Shearing Transformation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ipywidgets import interact, interactive, fixed, interact_manual\n",
|
||||
"import ipywidgets as widgets\n",
|
||||
"from shear import shear_transformation\n",
|
||||
"def draw_mesh_after_shear_transformation(V, F, nu):\n",
|
||||
" V1 = shear_transformation(V, nu)\n",
|
||||
" draw_mesh_with_centroid(V1, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "89d3fc02da0847b598183789c019b6da",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"interactive(children=(FloatSlider(value=0.0, description='nu', max=1.0, min=-1.0), Output()), _dom_classes=('w…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"interact(draw_mesh_after_shear_transformation, V = fixed(V), F = fixed(F), nu = (-1, 1, 0.1));"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 5. Shear Equilibrium"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from shear import shear_equilibrium\n",
|
||||
"from geometry import compute_center_support_line\n",
|
||||
"def compute_equilibrium_mesh(V, F):\n",
|
||||
" x_csl = compute_center_support_line(V)\n",
|
||||
" V1 = shear_equilibrium(V, F, x_csl)\n",
|
||||
" draw_mesh_with_centroid(V1, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Copy the following codes and find equilibrium shapes for all other examples in ../data folder "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "9a4f8c51812b477ea4a39f964a209826",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.3502894…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"with open('../data/dance.json', 'r') as infile:\n",
|
||||
" [V, F] = json.load(infile)\n",
|
||||
" V = np.array(V)\n",
|
||||
" F = np.array(F)\n",
|
||||
" compute_equilibrium_mesh(V, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "37e4dae7a1c540a4899ae36f48424cc3",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.3594106…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"with open('../data/dinosaur.json', 'r') as infile:\n",
|
||||
" [V, F] = json.load(infile)\n",
|
||||
" V = np.array(V)\n",
|
||||
" F = np.array(F)\n",
|
||||
" compute_equilibrium_mesh(V, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "ae4038d1f44949b08cf9bb12b2f55d22",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.0364573…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"with open('../data/fans.json', 'r') as infile:\n",
|
||||
" [V, F] = json.load(infile)\n",
|
||||
" V = np.array(V)\n",
|
||||
" F = np.array(F)\n",
|
||||
" compute_equilibrium_mesh(V, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "ebee92986c1b47b683c696990b8bb13b",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.4445750…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"with open('../data/gym.json', 'r') as infile:\n",
|
||||
" [V, F] = json.load(infile)\n",
|
||||
" V = np.array(V)\n",
|
||||
" F = np.array(F)\n",
|
||||
" compute_equilibrium_mesh(V, F)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "gc_course_env",
|
||||
"language": "python",
|
||||
"name": "gc_course_env"
|
||||
},
|
||||
"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": 4
|
||||
}
|
BIN
cs457-gc/assignment_1_1/problem131.pdf
Normal file
120
cs457-gc/assignment_1_1/src/geometry.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import numpy as np
|
||||
# -----------------------------------------------------------------------------
|
||||
# Mesh geometry
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
def compute_faces_area(V, F):
|
||||
"""
|
||||
Computes the area of the faces of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- area : np.array (|F|,)
|
||||
The area of the faces. The i-th position contains the area of the i-th
|
||||
face.
|
||||
"""
|
||||
|
||||
# HW1 1.3.3
|
||||
trig_area = lambda fi: ((V[fi[0]][1] - V[fi[1]][1]) * V[fi[2]][0]+ (V[fi[2]][1] - V[fi[0]][1]) * V[fi[1]][0] + (V[fi[1]][1] - V[fi[2]][1]) * V[fi[0]][0])/2.0
|
||||
area = np.array([trig_area(fi) for fi in F])
|
||||
return area
|
||||
|
||||
|
||||
def compute_mesh_area(V, F):
|
||||
"""
|
||||
Computes the area of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- area : float
|
||||
The area of the mesh.
|
||||
"""
|
||||
|
||||
# HW1 1.3.3
|
||||
area = np.sum(compute_faces_area(V,F))
|
||||
|
||||
return area
|
||||
|
||||
|
||||
def compute_faces_centroid(V, F):
|
||||
"""
|
||||
Computes the area centroid of each face of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- cf : np.array (|F|, 3)
|
||||
The area centroid of the faces.
|
||||
"""
|
||||
|
||||
# HW1 1.3.4
|
||||
cent_x = lambda fi: (V[fi[0]][0] + V[fi[1]][0] + V[fi[2]][0])/3.0
|
||||
cent_y = lambda fi: (V[fi[0]][1] + V[fi[1]][1] + V[fi[2]][1])/3.0
|
||||
cent_idx = lambda fi: [cent_x(fi), cent_y(fi), 0]
|
||||
|
||||
cf = np.array([cent_idx(fi) for fi in F])
|
||||
|
||||
return cf
|
||||
|
||||
|
||||
def compute_mesh_centroid(V, F):
|
||||
"""
|
||||
Computes the area centroid of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- centroid : np.array (3,)
|
||||
The area centroid of the mesh.
|
||||
"""
|
||||
|
||||
# HW1 1.3.4
|
||||
face_centroid = compute_faces_centroid(V,F)
|
||||
mesh_area= compute_mesh_area(V,F)
|
||||
face_area = compute_faces_area(V,F)
|
||||
|
||||
face_centroid_x = face_centroid[:,0]
|
||||
face_centroid_y = face_centroid[:,1]
|
||||
face_centroid_z = face_centroid[:,2]
|
||||
|
||||
mc = np.array([np.sum(np.dot(face_centroid_x,face_area))/mesh_area, np.sum(np.dot(face_centroid_y,face_area))/mesh_area, 0])
|
||||
|
||||
return mc
|
||||
|
||||
def compute_center_support_line(V):
|
||||
"""
|
||||
Computes the x coordinate of the center of the support line
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
|
||||
Output:
|
||||
- x_csl : float
|
||||
the x coordinate of the center of the support line
|
||||
"""
|
||||
|
||||
# HW1 1.3.5
|
||||
support_v = np.fromiter((v[0] for v in V if v[1]<10**-5), dtype=V.dtype)
|
||||
x_csl = np.amin(support_v)+(np.amax(support_v)-np.amin(support_v))/2
|
||||
|
||||
return x_csl
|
64
cs457-gc/assignment_1_1/src/shear.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import numpy as np
|
||||
from geometry import compute_mesh_centroid
|
||||
# -----------------------------------------------------------------------------
|
||||
# Mesh geometry
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
def shear_transformation(V, nu):
|
||||
"""
|
||||
Computes vertices' postion after the shear transformation.
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- nu : the shear paramter
|
||||
|
||||
Output:
|
||||
- V1 : np.array (|V|, 3)
|
||||
The array of vertices positions after transformation.
|
||||
"""
|
||||
|
||||
# HW1 1.3.6
|
||||
nu_mat = np.array([[1,nu,0],[0,1,0],[0,0,1]])
|
||||
V1 = np.matmul(nu_mat,V.T).T
|
||||
|
||||
return V1
|
||||
|
||||
|
||||
def shear_equilibrium(V, F, x_csl):
|
||||
"""
|
||||
Shear the input mesh to make it equilibrium.
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
- x_csl: np.array (3, )
|
||||
The x coordinate of the target centroid
|
||||
Output:
|
||||
- V1 : np.array (|V|, 3)
|
||||
The array of vertices positions that are equilibrium.
|
||||
"""
|
||||
V1 = V.copy()
|
||||
|
||||
# HW1 1.3.7
|
||||
nu = 0.0;
|
||||
step = 0.5;
|
||||
cent = compute_mesh_centroid(V1,F)
|
||||
csl = cent[0]
|
||||
|
||||
while(abs(csl-x_csl) > 10**-5 and step > 10**-5):
|
||||
if(csl > x_csl):
|
||||
nu -= step;
|
||||
else:
|
||||
nu += step;
|
||||
|
||||
V1 = shear_transformation(V,nu)
|
||||
cent = compute_mesh_centroid(V1,F)
|
||||
csl = cent[0]
|
||||
step = step/2.0;
|
||||
|
||||
return V1
|
79
cs457-gc/assignment_1_1/test/test1.py
Normal file
@@ -0,0 +1,79 @@
|
||||
# import pytest
|
||||
import pytest
|
||||
import json
|
||||
import sys
|
||||
import numpy as np
|
||||
sys.path.append('../')
|
||||
sys.path.append('../src')
|
||||
from src.geometry import *
|
||||
from src.shear import *
|
||||
|
||||
eps = 1E-6
|
||||
|
||||
with open('test_data1.json', 'r') as infile:
|
||||
homework_datas = json.load(infile)
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[0])
|
||||
def test_faces_centroid(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
F = np.array(data[1], dtype=int)
|
||||
centroid_ground_truth = np.array(data[2])
|
||||
centroid_student = compute_faces_centroid(V, F)
|
||||
assert np.linalg.norm(centroid_ground_truth - centroid_student) < eps
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[1])
|
||||
def test_faces_area(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
F = np.array(data[1], dtype=int)
|
||||
area_ground_truth = np.array(data[2])
|
||||
area_student = compute_faces_area(V, F)
|
||||
assert np.linalg.norm(area_ground_truth - area_student) < eps
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[2])
|
||||
def test_mesh_centroid(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
F = np.array(data[1], dtype=int)
|
||||
centroid_ground_truth = np.array(data[2])
|
||||
centroid_student = compute_mesh_centroid(V, F)
|
||||
assert np.linalg.norm(centroid_ground_truth - centroid_student) < eps
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[3])
|
||||
def test_mesh_area(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
F = np.array(data[1], dtype=int)
|
||||
area_ground_truth = np.array(data[2])
|
||||
area_student = compute_mesh_area(V, F)
|
||||
assert abs(area_ground_truth - area_student) < eps
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[4])
|
||||
def test_center_support_line(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
F = np.array(data[1], dtype=int)
|
||||
support_line_ground_truth = np.array(data[2])
|
||||
support_line_student = compute_center_support_line(V)
|
||||
assert abs(support_line_ground_truth - support_line_student) < eps
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[5])
|
||||
def test_shear_tranformation(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
F = np.array(data[1], dtype=int)
|
||||
nu = data[2]
|
||||
V_shear_ground_truth = np.array(data[3], dtype=float)
|
||||
V_shear_student = shear_transformation(V, nu)
|
||||
assert np.linalg.norm(V_shear_student - V_shear_ground_truth) < eps
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[6])
|
||||
def test_shear_equilibrium(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
F = np.array(data[1], dtype=int)
|
||||
x_csl = data[2]
|
||||
V_shear_ground_truth = np.array(data[3], dtype=float)
|
||||
V_shear_student = shear_equilibrium(V, F, x_csl)
|
||||
assert np.linalg.norm(V_shear_student - V_shear_ground_truth) < eps
|
1
cs457-gc/assignment_1_1/test/test_data1.json
Normal file
@@ -0,0 +1 @@
|
||||
[[[[[0, 0, 0], [1, 0, 0], [0, 1, 0]], [[0, 1, 2]], [[0.3333333333333333, 0.3333333333333333, 0]]]], [[[[0, 0, 0], [1, 0, 0], [0, 1, 0]], [[0, 1, 2]], [0.5]]], [[[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], [[0, 1, 2], [1, 3, 2]], [[0.5, 0.5, 0]]]], [[[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], [[0, 1, 2], [1, 3, 2]], 1]], [[[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], [[0, 1, 2], [1, 3, 2]], 0.5]], [[[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], [[0, 1, 2], [1, 3, 2]], 0.5, [[0, 0, 0], [1, 0, 0], [0.5, 1, 0], [1.5, 1, 0]]]], [[[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], [[0, 1, 2], [1, 3, 2]], 0.75, [[0, 0, 0], [1, 0, 0], [0.5, 1, 0], [1.5, 1, 0]]]]]
|
1
cs457-gc/assignment_1_2/data/dance.json
Normal file
1
cs457-gc/assignment_1_2/data/dinosaur.json
Normal file
1
cs457-gc/assignment_1_2/data/gym.json
Normal file
BIN
cs457-gc/assignment_1_2/notebook/errors.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
cs457-gc/assignment_1_2/notebook/gradient_area_01.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
cs457-gc/assignment_1_2/notebook/gradient_area_02.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
cs457-gc/assignment_1_2/notebook/gradient_equilibrium.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
cs457-gc/assignment_1_2/notebook/gradient_shape.png
Normal file
After Width: | Height: | Size: 45 KiB |
758
cs457-gc/assignment_1_2/notebook/make_it_stand_nb2_student.ipynb
Normal file
244
cs457-gc/assignment_1_2/src/energies.py
Normal file
@@ -0,0 +1,244 @@
|
||||
import numpy as np
|
||||
from scipy import sparse
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Functions from assignment_1_1
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
from geometry import compute_mesh_centroid
|
||||
from geometry import compute_faces_centroid
|
||||
from geometry import compute_faces_area
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Provided functions
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def vertex_cells_sum(values, cells):
|
||||
"""
|
||||
Sums values at vertices from each incident n-cell.
|
||||
|
||||
Input:
|
||||
- values : np.array (#cells,) or (#cells, n)
|
||||
The cell values to be summed at vertices.
|
||||
If shape (#cells,): The value is per-cell,
|
||||
If shape (#cells, n): The value refers to the corresponding cell vertex.
|
||||
- cells : np.array (#cells, n)
|
||||
The array of cells.
|
||||
Output:
|
||||
- v_sum : np.array (#vertices,)
|
||||
A vector with the sum at each i-th vertex in i-th position.
|
||||
Note:
|
||||
If n = 2 the cell is an edge, if n = 3 the cell is a triangle,
|
||||
if n = 4 the cell can be a tetrahedron or a quadrilateral, depending on
|
||||
the data structure.
|
||||
"""
|
||||
i = cells.flatten('F')
|
||||
j = np.arange(len(cells))
|
||||
j = np.tile(j, cells.shape[1])
|
||||
v = values.flatten('F')
|
||||
if len(v) == len(cells):
|
||||
v = v[j]
|
||||
v_sum = sparse.coo_matrix((v, (i, j)), (np.max(cells) + 1, len(cells)))
|
||||
return np.array(v_sum.sum(axis=1)).flatten()
|
||||
|
||||
|
||||
def compute_edges_length(V, E):
|
||||
"""
|
||||
Computes the edge length of each mesh edge.
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- E : np.array (#edges, 2)
|
||||
The array of mesh edges.
|
||||
generated from the function E = igl.edges(F)
|
||||
returns an array (#edges, 2) where i-th row contains the indices of the two vertices of i-th edge.
|
||||
Output:
|
||||
- l : np.array (#edges,)
|
||||
The edge lengths.
|
||||
"""
|
||||
|
||||
l = np.linalg.norm(V[E[:, 0]] - V[E[:, 1]], axis=1)
|
||||
return l
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 2.5.1 Target energies
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def compute_equilibrium_energy(V, F, x_csl):
|
||||
"""
|
||||
Computes the equilibrium energy E_eq = 1/2*(x_cm - x_csl)^2.
|
||||
|
||||
Input:
|
||||
-- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
Output:
|
||||
- E_eq : float
|
||||
the equilibrium energy of the mesh with respect to the target centroid
|
||||
x_csl.
|
||||
"""
|
||||
x_cm = compute_mesh_centroid(V,F)[0]
|
||||
E_eq = 0.5 * (x_cm - x_csl)**2
|
||||
return E_eq
|
||||
|
||||
|
||||
def compute_shape_energy(V, E, L):
|
||||
"""
|
||||
Computes the energy E_sh = 1/2 sum_e (l_e - L_e)^2 in the current
|
||||
configuration V, where l_e is the length of mesh edges, and L_e the
|
||||
corresponding length in the undeformed configuration.
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- E : np.array (#edges, 2)
|
||||
The array of mesh edges.
|
||||
- L : np.array (#edges,)
|
||||
The rest lengths of mesh edges.
|
||||
Output:
|
||||
- E_sh : float
|
||||
The energy E_sh in the current configuration V.
|
||||
"""
|
||||
l = compute_edges_length(V,E)
|
||||
Lf = np.array(L)
|
||||
e_vec = np.arange(len(E))
|
||||
ldiff = (l[e_vec]-Lf[e_vec])**2
|
||||
E_sh = 0.5 * np.sum(ldiff)
|
||||
return E_sh
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 2.5.2 Faces area gradient
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def compute_faces_area_gradient(V, F):
|
||||
"""
|
||||
Computes the gradient of faces area.
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- dA_x : np.array (#F, 3)
|
||||
The gradient of faces areas A_i with respect to the x coordinate of each
|
||||
face vertex x_1, x_2, and x_3, with (i,0) = dA_i/dx_1, (i,1) = dA_i/dx_2,
|
||||
and (i,2) = dA_i/dx_3.
|
||||
- dA_y : np.array (#F, 3)
|
||||
The gradient of faces areas A_i with respect to the y coordinate of each
|
||||
face vertex y_1, y_2, and y_3, with (i,0) = dA_i/dy_1, (i,1) = dA_i/dy_2,
|
||||
and (i,2) = dA_i/dy_3.
|
||||
"""
|
||||
|
||||
grad = lambda a,b: (V[a]-V[b])
|
||||
gradABC = lambda fi: [grad(fi[2],fi[1]),grad(fi[0],fi[2]),grad(fi[1],fi[0])]
|
||||
dA = np.apply_along_axis(gradABC,1,F)/2
|
||||
|
||||
dA_x = -dA[:,:,1]
|
||||
dA_y = dA[:,:,0]
|
||||
return dA_x, dA_y
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 2.5.3 Equilibrium energy gradient
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def compute_equilibrium_energy_gradient(V, F, x_csl):
|
||||
"""
|
||||
Computes the gradient of the energy E_eq = 1/2*(x_cm - x_csl)^2 with respect
|
||||
to the x and y coordinates of each vertex, where x_cm is the x coordinate
|
||||
of the area centroid and x_csl x coordinate of the center of the support
|
||||
line.
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
Output:
|
||||
- grad_E_eq : np.array (#V, 2)
|
||||
The gradient of the energy E_eq with respect to vertices v_i,
|
||||
with (i, 0) = dE_eq/dx_i and (i, 1) = dE_eq/dy_i
|
||||
"""
|
||||
|
||||
cm = compute_mesh_centroid(V,F)
|
||||
x_cm = cm[0]
|
||||
|
||||
x_f = compute_faces_centroid(V,F)
|
||||
|
||||
A_f = compute_faces_area(V,F)
|
||||
|
||||
A_f_V_nonp = compute_faces_area_gradient(V, F)
|
||||
A_f_V = np.stack(A_f_V_nonp,axis=-1)
|
||||
|
||||
A_omega = np.sum(A_f)
|
||||
xfact = (x_cm - x_csl)/A_omega
|
||||
|
||||
xfV = lambda v: np.apply_along_axis(lambda x: np.array([1/3,0.0]) if np.any(x[:]==v) else np.zeros((2)),1,F)
|
||||
|
||||
AfV = lambda v: (np.where(F[:,0][:,None]==v,A_f_V[:,0,:2],
|
||||
np.where(F[:,1][:,None]==v,A_f_V[:,1,:2],
|
||||
np.where(F[:,2][:,None]==v,A_f_V[:,2,:2],np.zeros((F.shape[0],2))) )) )
|
||||
|
||||
cf = lambda v : AfV(v)*(x_f[:,0] - x_cm)[:, None] + (A_f[:, None]*xfV(v))
|
||||
|
||||
#v_vec = np.arange(len(V))
|
||||
#veq = np.sum(cf(v_vec),axis=0)*xfact
|
||||
veq = np.array([np.sum(cf(v),axis=0) for v in range(0,len(V))])*xfact
|
||||
|
||||
return veq
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 2.5.4 Shape energy gradient
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def compute_shape_energy_gradient(V, E, L):
|
||||
"""
|
||||
Computes the gradient of the energy E_sh = 1/2 sum_e (l_e - L_e)^2 with
|
||||
respect to the x and y coordinates of each vertex, where l_e is the length
|
||||
of mesh edges, and L_e the corresponding length in the undeformed
|
||||
configuration.
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- E : np.array (#edges, 2)
|
||||
The array of mesh edges.
|
||||
- L : np.array (#edges,)
|
||||
The rest lengths of mesh edges.
|
||||
Output:
|
||||
- grad_E_sh : np.array (#V, 2)
|
||||
The gradient of the energy E_sh with respect to vertices v_i,
|
||||
with (i, 0) = dE_sh/dx_i, (i, 1) = dE_sh/dy_i
|
||||
"""
|
||||
|
||||
vdif = lambda ee0, ee1: (V[ee0]-V[ee1])[:,:2]
|
||||
len_e_d = vdif(E[:,0],E[:,1])
|
||||
len_e = np.linalg.norm(len_e_d, axis=1)
|
||||
|
||||
len_e_t = lambda v: (np.where(E[:,0][:,None]==v,len_e_d[:],
|
||||
np.where(E[:,1][:,None]==v,-len_e_d[:],np.zeros(E.shape))))
|
||||
|
||||
veq = np.sum(np.array([len_e_t(v) for v in range(0,len(V))]),axis=1) - np.sum(L/len_e,axis=0)
|
||||
|
||||
return veq
|
100
cs457-gc/assignment_1_2/src/geometry.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import numpy as np
|
||||
|
||||
def compute_faces_area(V, F):
|
||||
"""
|
||||
Computes the area of the faces of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- area : np.array (|F|,)
|
||||
The area of the faces. The i-th position contains the area of the i-th
|
||||
face.
|
||||
"""
|
||||
|
||||
# HW.1.3.3
|
||||
return np.linalg.norm(np.cross(V[F[:,1]] - V[F[:,0]],V[F[:,2]] - V[F[:,0]], axis=1), axis=1)/2.0
|
||||
|
||||
|
||||
def compute_mesh_area(V, F):
|
||||
"""
|
||||
Computes the area of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- area : float
|
||||
The area of the mesh.
|
||||
"""
|
||||
|
||||
# HW.1.3.3
|
||||
return np.sum(compute_faces_area(V,F))
|
||||
|
||||
|
||||
def compute_faces_centroid(V, F):
|
||||
"""
|
||||
Computes the area centroid of each face of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- cf : np.array (|F|, 3)
|
||||
The area centroid of the faces.
|
||||
"""
|
||||
|
||||
# HW.1.3.4
|
||||
return (V[F[:,0]]+ V[F[:,1]] + V[F[:,2]])/3.0
|
||||
|
||||
|
||||
def compute_mesh_centroid(V, F):
|
||||
"""
|
||||
Computes the area centroid of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- centroid : np.array (3,)
|
||||
The area centroid of the mesh.
|
||||
"""
|
||||
|
||||
# HW.1.3.4
|
||||
face_centroid = compute_faces_centroid(V,F)
|
||||
face_area = compute_faces_area(V,F)
|
||||
return 1.0/np.sum(face_area) * np.sum(np.einsum('i,ij->ij', face_area, face_centroid), axis=0)
|
||||
|
||||
|
||||
def compute_center_support_line(V):
|
||||
"""
|
||||
Computes the x coordinate of the center of the support line
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
|
||||
Output:
|
||||
- x_csl : float
|
||||
the x coordinate of the center of the support line
|
||||
"""
|
||||
|
||||
# HW.1.3.5
|
||||
support_v = np.fromiter((v[0] for v in V if v[1]<10**-5), dtype=V.dtype)
|
||||
x_csl = np.amin(support_v)+(np.amax(support_v)-np.amin(support_v))/2
|
||||
|
||||
return x_csl
|
138
cs457-gc/assignment_1_2/src/optimization.py
Normal file
@@ -0,0 +1,138 @@
|
||||
from energies import compute_edges_length
|
||||
from energies import compute_equilibrium_energy_gradient, compute_equilibrium_energy
|
||||
from energies import compute_shape_energy_gradient, compute_shape_energy
|
||||
from geometry import compute_mesh_centroid
|
||||
import numpy as np
|
||||
import time
|
||||
import igl
|
||||
|
||||
def compute_optimization_objective(V, F, E, x_csl, L0, w):
|
||||
"""
|
||||
Compute the objective function of make-it-stand problem.
|
||||
E = E_equilibrium + w * E_shape
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- E : np.array (#edges, 2)
|
||||
The array of mesh edges.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
- L0 : np.array (#edges,)
|
||||
The rest lengths of mesh edges.
|
||||
- w : float
|
||||
The weight for shape preservation energy.
|
||||
Output:
|
||||
- obj : float
|
||||
The value of the objective function.
|
||||
"""
|
||||
|
||||
E_eq = compute_equilibrium_energy(V, F, x_csl)
|
||||
E_sh = compute_shape_energy(V, E, L0)
|
||||
obj = E_eq + w*E_sh
|
||||
|
||||
return obj
|
||||
|
||||
def compute_optimization_objective_gradient(V, F, E, x_csl, L0, w):
|
||||
"""
|
||||
Compute the gradient of the objective function of make-it-stand problem.
|
||||
D_E = D_E_equilibrium + w * D_E_shape
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- E : np.array (#edges, 2)
|
||||
The array of mesh edges.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
- l0 : np.array (#edges,)
|
||||
The rest lengths of mesh edges.
|
||||
- w : float
|
||||
The weight for shape preservation energy.
|
||||
Output:
|
||||
- grad_obj : np.array (#V, 2)
|
||||
The gradient of objective function.
|
||||
"""
|
||||
|
||||
grad_E_eq = compute_equilibrium_energy_gradient(V, F, x_csl)
|
||||
grad_E_sh = compute_shape_energy_gradient(V, E, L0)
|
||||
grad_obj = grad_E_eq + w * grad_E_sh
|
||||
|
||||
return grad_obj
|
||||
|
||||
def fixed_step_gradient_descent(V, F, x_csl, w, theta, iters):
|
||||
"""
|
||||
Find equilibrium shape by using fixed step gradient descent method
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
- w : float
|
||||
The weight for shape preservation energy.
|
||||
- theta : float
|
||||
The optimization step.
|
||||
- iters : int
|
||||
The number of iteration for gradient descent.
|
||||
|
||||
Output:
|
||||
- V1 : np.array (#V, 3)
|
||||
The optimized mesh's vertices
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- energy: np.array(iters, 1)
|
||||
The objective function energy curve with respect to the number of iterations.
|
||||
- running_time: float
|
||||
The tot running time of the optimization
|
||||
"""
|
||||
|
||||
V1 = V.copy()
|
||||
|
||||
# this function of libigl returns an array (#edges, 2) where i-th row
|
||||
# contains the indices of the two vertices of i-th edge.
|
||||
E = igl.edges(F)
|
||||
|
||||
fix = np.where(V1[:, 1] < 1e-3)[0]
|
||||
|
||||
L0 = compute_edges_length(V1, E)
|
||||
|
||||
t0 = time.time()
|
||||
|
||||
energy = []
|
||||
|
||||
for i in range(iters):
|
||||
|
||||
grad = compute_optimization_objective_gradient(V1, F, E, x_csl, L0, w)
|
||||
|
||||
obj = compute_optimization_objective(V1, F, E, x_csl, L0, w)
|
||||
|
||||
energy.append(obj)
|
||||
|
||||
grad[fix] = 0
|
||||
|
||||
### start of your code.
|
||||
x_cm = compute_mesh_centroid(V, F)[0]
|
||||
if abs(x_csl - x_cm)<=10**-3:
|
||||
break
|
||||
if (np.linalg.norm(grad)<=10**-3):
|
||||
break
|
||||
|
||||
# grad_f = grad[:,3
|
||||
grad_f = np.zeros((np.shape(grad)[0],3))
|
||||
grad_f[:,:-1] = grad
|
||||
V1 = V1 -(theta * grad_f)
|
||||
### end of your code.
|
||||
|
||||
running_time = time.time() - t0
|
||||
|
||||
return [V1, F, energy, running_time]
|
87
cs457-gc/assignment_1_2/test/test2.py
Normal file
@@ -0,0 +1,87 @@
|
||||
# import pytest
|
||||
import time
|
||||
import pytest
|
||||
import json
|
||||
import sys
|
||||
import igl
|
||||
import numpy as np
|
||||
sys.path.append('../')
|
||||
sys.path.append('../src')
|
||||
from src.energies import *
|
||||
eps = 1E-6
|
||||
|
||||
with open('test_data2.json', 'r') as infile:
|
||||
homework_datas = json.load(infile)
|
||||
|
||||
# @pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[0])
|
||||
def test_shape_energy_correctness(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
E = np.array(data[1], dtype=int)
|
||||
l0 = np.array(data[2], dtype=float)
|
||||
shape_energy_ground_truth = np.array(data[3])
|
||||
shape_energy_student = compute_shape_energy(V, E, l0)
|
||||
assert np.linalg.norm(shape_energy_ground_truth - shape_energy_student) < eps
|
||||
|
||||
# @pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[1])
|
||||
def test_equilibrium_engery_correctness(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
F = np.array(data[1], dtype=int)
|
||||
x_csl = data[2]
|
||||
equilibrium_engery_ground_truth = np.array(data[3])
|
||||
equilibrium_engery_student = compute_equilibrium_energy(V, F, x_csl)
|
||||
assert np.linalg.norm(equilibrium_engery_ground_truth - equilibrium_engery_student) < eps
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[2])
|
||||
def test_faces_area_gradient_correctness(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
F = np.array(data[1], dtype=int)
|
||||
faces_area_gradient_ground_truth_x = np.array(data[2])
|
||||
faces_area_gradient_ground_truth_y = np.array(data[3])
|
||||
[faces_area_gradient_student_x, faces_area_gradient_student_y] = compute_faces_area_gradient(V, F)
|
||||
assert np.linalg.norm(faces_area_gradient_ground_truth_x - faces_area_gradient_student_x) < eps \
|
||||
and np.linalg.norm(faces_area_gradient_ground_truth_y - faces_area_gradient_student_y) < eps
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[3])
|
||||
def test_equilibrium_energy_gradient_correctness(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
F = np.array(data[1], dtype=int)
|
||||
x_csl = data[2]
|
||||
equilibrium_energy_gradient = np.array(data[3])
|
||||
equilibrium_energy_student = compute_equilibrium_energy_gradient(V, F, x_csl)
|
||||
assert np.linalg.norm(equilibrium_energy_gradient - equilibrium_energy_student) < eps
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[4])
|
||||
def test_shape_energy_gradient_correctness(data):
|
||||
V = np.array(data[0], dtype=float)
|
||||
E = np.array(data[1], dtype=int)
|
||||
l0 = np.array(data[2], dtype=float)
|
||||
shape_energy_gradient_ground_truth = np.array(data[3])
|
||||
shape_energy_gradient_student = compute_shape_energy_gradient(V, E, l0)
|
||||
assert np.linalg.norm(shape_energy_gradient_ground_truth - shape_energy_gradient_student) < eps
|
||||
|
||||
n = 100000
|
||||
F_big = np.arange(3 * n).reshape((n, 3))
|
||||
V_big = np.random.random((3 * n, 3))
|
||||
l0_big = np.zeros(3 * n)
|
||||
E_big = igl.edges(F_big)
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
def test_shape_energy_timing():
|
||||
compute_shape_energy(V_big, E_big, l0_big)
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
def test_faces_area_gradient_timing():
|
||||
compute_faces_area_gradient(V_big, F_big)
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
def test_equilibrium_energy_gradient_timing():
|
||||
compute_equilibrium_energy_gradient(V_big, F_big, 0)
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
def test_shape_energy_gradient_timing():
|
||||
compute_shape_energy_gradient(V_big, E_big, l0_big)
|
1
cs457-gc/assignment_1_2/test/test_data2.json
Normal file
@@ -0,0 +1 @@
|
||||
[[[[[0, 0, 0], [1, 0, 0], [0, 1, 0]], [[0, 1], [0, 2], [1, 2]], [0.0, 0.0, 0.0], 2.0], [[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], [[0, 1], [0, 2], [1, 2], [1, 3], [2, 3]], [0.0, 0.0, 0.0, 0.0, 0.0], 3.0]], [[[[0, 0, 0], [1, 0, 0], [0, 1, 0]], [[0, 1, 2]], 0, 0.05555555555555555], [[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], [[0, 1, 2], [1, 3, 2]], 0, 0.125]], [[[[0, 0, 0], [1, 0, 0], [0, 1, 0]], [[0, 1, 2]], [[-0.5, 0.5, -0.0]], [[-0.5, -0.0, 0.5]]], [[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], [[0, 1, 2], [1, 3, 2]], [[-0.5, 0.5, -0.0], [-0.0, 0.5, -0.5]], [[-0.5, -0.0, 0.5], [-0.5, 0.5, -0.0]]]], [[[[0, 0, 0], [1, 0, 0], [0, 1, 0]], [[0, 1, 2]], 0, [[0.1111111111111111, 0.0], [0.1111111111111111, 0.0], [0.1111111111111111, 0.0]]], [[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], [[0, 1, 2], [1, 3, 2]], 0, [[0.125, 0.04166666666666667], [0.12499999999999999, -0.04166666666666666], [0.125, -0.04166666666666667], [0.12499999999999999, 0.04166666666666666]]]], [[[[0, 0, 0], [1, 0, 0], [0, 1, 0]], [[0, 1], [0, 2], [1, 2]], [0.0, 0.0, 0.0], [[-1.0, -1.0], [2.0, -1.0], [-1.0, 2.0]]], [[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], [[0, 1], [0, 2], [1, 2], [1, 3], [2, 3]], [0.0, 0.0, 0.0, 0.0, 0.0], [[-1.0, -1.0], [2.0, -2.0], [-2.0, 2.0], [1.0, 1.0]]]]]
|
1
cs457-gc/assignment_1_3/data/dance.json
Normal file
BIN
cs457-gc/assignment_1_3/data/dance.png
Normal file
After Width: | Height: | Size: 123 KiB |
1
cs457-gc/assignment_1_3/data/dinosaur.json
Normal file
BIN
cs457-gc/assignment_1_3/data/dinosaur.png
Normal file
After Width: | Height: | Size: 143 KiB |
BIN
cs457-gc/assignment_1_3/data/drawA.png
Normal file
After Width: | Height: | Size: 31 KiB |
2
cs457-gc/assignment_1_3/data/drawA.svg
Normal file
After Width: | Height: | Size: 91 KiB |
BIN
cs457-gc/assignment_1_3/data/drawB.png
Normal file
After Width: | Height: | Size: 45 KiB |
2
cs457-gc/assignment_1_3/data/drawB.svg
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
cs457-gc/assignment_1_3/data/drawC.png
Normal file
After Width: | Height: | Size: 29 KiB |
2
cs457-gc/assignment_1_3/data/drawC.svg
Normal file
After Width: | Height: | Size: 67 KiB |
1
cs457-gc/assignment_1_3/data/gym.json
Normal file
937
cs457-gc/assignment_1_3/notebook/make_it_stand_nb3.ipynb
Normal file
188
cs457-gc/assignment_1_3/src/bfgs.py
Normal file
@@ -0,0 +1,188 @@
|
||||
from energies import *
|
||||
from optimization import compute_optimization_objective, compute_optimization_objective_gradient
|
||||
from linesearch import *
|
||||
import numpy as np
|
||||
import time
|
||||
import igl
|
||||
|
||||
def compute_approximate_hessian_matrix(sk, yk, B_prev):
|
||||
"""
|
||||
Compute the approximated hessian matrix
|
||||
|
||||
Input:
|
||||
- s_k : np.array(#V * 2, 1)
|
||||
s_k = x_{k+1} - x_{k}, the difference in variables at two consecutive iterations.
|
||||
Note that x_{k} is the vertices' coordinate V at the k-th iteration.
|
||||
The vertices' cooridnate V however is a np.array(#V, 3)
|
||||
We use x_{k} = V[:, 0 : 2].flatten() to flatten the vertices coordinartes.
|
||||
|
||||
- y_k : np.array(#V * 2, 1)
|
||||
y_k = grad(f(x_{k+1})) - grad(f(x_{k})),
|
||||
the difference in function gradient at two consecutive iterations.
|
||||
The grad(f(x_{k})) is the gradient of our objective energy,
|
||||
which is a np.array(#V, 2)
|
||||
To be used for BFGS, we flatten the gradient.
|
||||
The flatten process asks the all x coordinates to be first
|
||||
then all y cooridnates to be the second.
|
||||
|
||||
- B_prev: np.array(#V * 2, #V * 2)
|
||||
The approximated hessian matrix from last iteration
|
||||
|
||||
Output
|
||||
-B_new: np.array(#V * 2, #V * 2)
|
||||
The approximated hessian matrix of current iteration
|
||||
|
||||
"""
|
||||
a = (yk @ yk.T)/(yk.T @ sk)
|
||||
bt = B_prev @ sk @ sk.T @ B_prev.T
|
||||
bb = sk.T @ B_prev @ sk
|
||||
B_new = B_prev + a - bt/bb
|
||||
return B_new
|
||||
|
||||
def compute_inverse_approximate_hessian_matrix(sk, yk, invB_prev):
|
||||
"""
|
||||
Compute the inverse approximated hessian matrix
|
||||
|
||||
Input:
|
||||
- s_k : np.array(#V * 2, 1)
|
||||
s_k = x_{k+1} - x_{k}, the difference in variables at two consecutive iterations.
|
||||
Note that x_{k} is the vertices' coordinate V at the k-th iteration.
|
||||
The vertices' cooridnate V however is a np.array(#V, 3)
|
||||
We use x_{k} = V[:, 0 : 2].flatten() to flatten the vertices coordinartes.
|
||||
|
||||
- y_k : np.array(#V * 2, 1)
|
||||
y_k = grad(f(x_{k+1})) - grad(f(x_{k})),
|
||||
the difference in function gradient at two consecutive iterations.
|
||||
The grad(f(x_{k})) is the gradient of our objective energy,
|
||||
which is a np.array(#V, 2)
|
||||
To be used for BFGS, we flatten the gradient.
|
||||
The flatten process asks the all x coordinates to be first
|
||||
then all y cooridnates to be the second.
|
||||
|
||||
- invB_prev: np.array(#V * 2, #V * 2)
|
||||
The inversed matrix of the approximated hessian from last iteration
|
||||
|
||||
Output
|
||||
- invB_new: np.array(#V * 2, #V * 2)
|
||||
The inversed matrix of the approximated hessian at current iteration
|
||||
|
||||
"""
|
||||
d = sk.T @ yk
|
||||
e = invB_prev @ yk
|
||||
a = (d + (yk.T @ e)) * (sk @ sk.T)/(d * d)
|
||||
|
||||
b = ((e @ sk.T) + ((sk @ yk.T) @ invB_prev))/d
|
||||
invB_new = invB_prev + a - b
|
||||
return invB_new
|
||||
|
||||
|
||||
def bfgs_with_line_search(V, F, x_csl, w, obj_tol, theta, beta, c, iter):
|
||||
|
||||
"""
|
||||
Find equilibrium shape by using BFGS method
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
- w : float
|
||||
The weight for shape preservation energy.
|
||||
- obj_tol: float
|
||||
The termination condition for optimization.
|
||||
The program stop running if
|
||||
the absolute different between the objectives of two consecutive iterations is smaller than obj_tol
|
||||
- theta : float
|
||||
The initial gradient descent step size.
|
||||
- beta : float
|
||||
The backtracking ratio, alpha = beta * alpha
|
||||
- c: float
|
||||
The coefficient for armijo condition
|
||||
- iter : int
|
||||
The number of iteration for gradient descent.
|
||||
|
||||
Output:
|
||||
- V1 : np.array (#V, 3)
|
||||
The optimized mesh's vertices
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- energy: np.array(iters, 1)
|
||||
The objective function energy curve with respect to the number of iterations.
|
||||
- running_time: float
|
||||
The tot running time of the optimization
|
||||
"""
|
||||
|
||||
V1 = V.copy()
|
||||
|
||||
# this function of libigl returns an array (#edges, 2) where i-th row
|
||||
# contains the indices of the two vertices of i-th edge.
|
||||
E = igl.edges(F)
|
||||
|
||||
fix = np.where(V1[:, 1] < 1e-3)[0]
|
||||
|
||||
L0 = compute_edges_length(V1, E)
|
||||
|
||||
t0 = time.time()
|
||||
|
||||
energy = []
|
||||
|
||||
obj_prev = 0
|
||||
|
||||
it_time = 0
|
||||
gradprev= None
|
||||
vprev = V1
|
||||
Hprev = np.identity(V.shape[0]*2)/theta
|
||||
|
||||
while (True):
|
||||
|
||||
# energy
|
||||
obj = compute_optimization_objective(V1, F, E, x_csl, L0, w)
|
||||
|
||||
if abs(obj_prev - obj) < obj_tol:
|
||||
break
|
||||
|
||||
if it_time > iter:
|
||||
break
|
||||
|
||||
obj_prev = obj
|
||||
|
||||
energy.append(obj)
|
||||
|
||||
grad = compute_optimization_objective_gradient(V1, F, E, x_csl, L0, w)
|
||||
|
||||
grad[fix] = 0
|
||||
if gradprev is None:
|
||||
gradprev = grad
|
||||
### start of your code.
|
||||
gradf = grad.flatten()
|
||||
ff = F.flatten()
|
||||
vf = V[:, 0 : 2].flatten()
|
||||
unflatten = lambda x: np.concatenate((np.reshape(x,(V.shape[0],2)),np.zeros((V.shape[0],1))),axis=-1)
|
||||
|
||||
f = lambda x: compute_optimization_objective(unflatten(x), F, E, x_csl, L0, w)
|
||||
alpha = backtracking_line_search(-gradf, gradf, vf, theta, beta, c, f)
|
||||
x_cm = compute_mesh_centroid(V, F)[0]
|
||||
|
||||
HV = (V1 - vprev)[:,:2].flatten()[:,None]
|
||||
HG = (grad-gradprev).flatten()[:,None]
|
||||
|
||||
Hcur = compute_inverse_approximate_hessian_matrix(HV, HG, Hprev)
|
||||
d = np.concatenate((np.reshape(Hcur @ gradf,(V.shape[0],2)),np.zeros((V.shape[0],1))),axis=-1)
|
||||
|
||||
vprev = V1
|
||||
gradprev = grad
|
||||
Hprev = Hcur
|
||||
|
||||
V1 = V1 - (alpha * d)
|
||||
|
||||
|
||||
### end of your code.
|
||||
|
||||
it_time = it_time + 1
|
||||
|
||||
running_time = time.time() - t0
|
||||
|
||||
return [V1, F, energy, running_time]
|
244
cs457-gc/assignment_1_3/src/energies.py
Normal file
@@ -0,0 +1,244 @@
|
||||
import numpy as np
|
||||
from scipy import sparse
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Functions from assignment_1_1
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
from geometry import compute_mesh_centroid
|
||||
from geometry import compute_faces_centroid
|
||||
from geometry import compute_faces_area
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Provided functions
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def vertex_cells_sum(values, cells):
|
||||
"""
|
||||
Sums values at vertices from each incident n-cell.
|
||||
|
||||
Input:
|
||||
- values : np.array (#cells,) or (#cells, n)
|
||||
The cell values to be summed at vertices.
|
||||
If shape (#cells,): The value is per-cell,
|
||||
If shape (#cells, n): The value refers to the corresponding cell vertex.
|
||||
- cells : np.array (#cells, n)
|
||||
The array of cells.
|
||||
Output:
|
||||
- v_sum : np.array (#vertices,)
|
||||
A vector with the sum at each i-th vertex in i-th position.
|
||||
Note:
|
||||
If n = 2 the cell is an edge, if n = 3 the cell is a triangle,
|
||||
if n = 4 the cell can be a tetrahedron or a quadrilateral, depending on
|
||||
the data structure.
|
||||
"""
|
||||
i = cells.flatten('F')
|
||||
j = np.arange(len(cells))
|
||||
j = np.tile(j, cells.shape[1])
|
||||
v = values.flatten('F')
|
||||
if len(v) == len(cells):
|
||||
v = v[j]
|
||||
v_sum = sparse.coo_matrix((v, (i, j)), (np.max(cells) + 1, len(cells)))
|
||||
return np.array(v_sum.sum(axis=1)).flatten()
|
||||
|
||||
|
||||
def compute_edges_length(V, E):
|
||||
"""
|
||||
Computes the edge length of each mesh edge.
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- E : np.array (#edges, 2)
|
||||
The array of mesh edges.
|
||||
generated from the function E = igl.edges(F)
|
||||
returns an array (#edges, 2) where i-th row contains the indices of the two vertices of i-th edge.
|
||||
Output:
|
||||
- l : np.array (#edges,)
|
||||
The edge lengths.
|
||||
"""
|
||||
|
||||
l = np.linalg.norm(V[E[:, 0]] - V[E[:, 1]], axis=1)
|
||||
return l
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 2.5.1 Target energies
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def compute_equilibrium_energy(V, F, x_csl):
|
||||
"""
|
||||
Computes the equilibrium energy E_eq = 1/2*(x_cm - x_csl)^2.
|
||||
|
||||
Input:
|
||||
-- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
Output:
|
||||
- E_eq : float
|
||||
the equilibrium energy of the mesh with respect to the target centroid
|
||||
x_csl.
|
||||
"""
|
||||
x_cm = compute_mesh_centroid(V,F)[0]
|
||||
E_eq = 0.5 * (x_cm - x_csl)**2
|
||||
return E_eq
|
||||
|
||||
|
||||
def compute_shape_energy(V, E, L):
|
||||
"""
|
||||
Computes the energy E_sh = 1/2 sum_e (l_e - L_e)^2 in the current
|
||||
configuration V, where l_e is the length of mesh edges, and L_e the
|
||||
corresponding length in the undeformed configuration.
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- E : np.array (#edges, 2)
|
||||
The array of mesh edges.
|
||||
- L : np.array (#edges,)
|
||||
The rest lengths of mesh edges.
|
||||
Output:
|
||||
- E_sh : float
|
||||
The energy E_sh in the current configuration V.
|
||||
"""
|
||||
l = compute_edges_length(V,E)
|
||||
Lf = np.array(L)
|
||||
e_vec = np.arange(len(E))
|
||||
ldiff = (l[e_vec]-Lf[e_vec])**2
|
||||
E_sh = 0.5 * np.sum(ldiff)
|
||||
return E_sh
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 2.5.2 Faces area gradient
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def compute_faces_area_gradient(V, F):
|
||||
"""
|
||||
Computes the gradient of faces area.
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- dA_x : np.array (#F, 3)
|
||||
The gradient of faces areas A_i with respect to the x coordinate of each
|
||||
face vertex x_1, x_2, and x_3, with (i,0) = dA_i/dx_1, (i,1) = dA_i/dx_2,
|
||||
and (i,2) = dA_i/dx_3.
|
||||
- dA_y : np.array (#F, 3)
|
||||
The gradient of faces areas A_i with respect to the y coordinate of each
|
||||
face vertex y_1, y_2, and y_3, with (i,0) = dA_i/dy_1, (i,1) = dA_i/dy_2,
|
||||
and (i,2) = dA_i/dy_3.
|
||||
"""
|
||||
|
||||
grad = lambda a,b: (V[a]-V[b])
|
||||
gradABC = lambda fi: [grad(fi[2],fi[1]),grad(fi[0],fi[2]),grad(fi[1],fi[0])]
|
||||
dA = np.apply_along_axis(gradABC,1,F)/2
|
||||
|
||||
dA_x = -dA[:,:,1]
|
||||
dA_y = dA[:,:,0]
|
||||
return dA_x, dA_y
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 2.5.3 Equilibrium energy gradient
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def compute_equilibrium_energy_gradient(V, F, x_csl):
|
||||
"""
|
||||
Computes the gradient of the energy E_eq = 1/2*(x_cm - x_csl)^2 with respect
|
||||
to the x and y coordinates of each vertex, where x_cm is the x coordinate
|
||||
of the area centroid and x_csl x coordinate of the center of the support
|
||||
line.
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
Output:
|
||||
- grad_E_eq : np.array (#V, 2)
|
||||
The gradient of the energy E_eq with respect to vertices v_i,
|
||||
with (i, 0) = dE_eq/dx_i and (i, 1) = dE_eq/dy_i
|
||||
"""
|
||||
|
||||
cm = compute_mesh_centroid(V,F)
|
||||
x_cm = cm[0]
|
||||
|
||||
x_f = compute_faces_centroid(V,F)
|
||||
|
||||
A_f = compute_faces_area(V,F)
|
||||
|
||||
A_f_V_nonp = compute_faces_area_gradient(V, F)
|
||||
A_f_V = np.stack(A_f_V_nonp,axis=-1)
|
||||
|
||||
A_omega = np.sum(A_f)
|
||||
xfact = (x_cm - x_csl)/A_omega
|
||||
|
||||
xfV = lambda v: np.apply_along_axis(lambda x: np.array([1/3,0.0]) if np.any(x[:]==v) else np.zeros((2)),1,F)
|
||||
|
||||
AfV = lambda v: (np.where(F[:,0][:,None]==v,A_f_V[:,0,:2],
|
||||
np.where(F[:,1][:,None]==v,A_f_V[:,1,:2],
|
||||
np.where(F[:,2][:,None]==v,A_f_V[:,2,:2],np.zeros((F.shape[0],2))) )) )
|
||||
|
||||
cf = lambda v : AfV(v)*(x_f[:,0] - x_cm)[:, None] + (A_f[:, None]*xfV(v))
|
||||
|
||||
#v_vec = np.arange(len(V))
|
||||
#veq = np.sum(cf(v_vec),axis=0)*xfact
|
||||
veq = np.array([np.sum(cf(v),axis=0) for v in range(0,len(V))])*xfact
|
||||
|
||||
return veq
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 2.5.4 Shape energy gradient
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def compute_shape_energy_gradient(V, E, L):
|
||||
"""
|
||||
Computes the gradient of the energy E_sh = 1/2 sum_e (l_e - L_e)^2 with
|
||||
respect to the x and y coordinates of each vertex, where l_e is the length
|
||||
of mesh edges, and L_e the corresponding length in the undeformed
|
||||
configuration.
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- E : np.array (#edges, 2)
|
||||
The array of mesh edges.
|
||||
- L : np.array (#edges,)
|
||||
The rest lengths of mesh edges.
|
||||
Output:
|
||||
- grad_E_sh : np.array (#V, 2)
|
||||
The gradient of the energy E_sh with respect to vertices v_i,
|
||||
with (i, 0) = dE_sh/dx_i, (i, 1) = dE_sh/dy_i
|
||||
"""
|
||||
|
||||
vdif = lambda ee0, ee1: (V[ee0]-V[ee1])[:,:2]
|
||||
len_e_d = vdif(E[:,0],E[:,1])
|
||||
len_e = np.linalg.norm(len_e_d, axis=1)
|
||||
|
||||
len_e_t = lambda v: (np.where(E[:,0][:,None]==v,len_e_d[:],
|
||||
np.where(E[:,1][:,None]==v,-len_e_d[:],np.zeros(E.shape))))
|
||||
|
||||
veq = np.sum(np.array([len_e_t(v) for v in range(0,len(V))]),axis=1) - np.sum(L/len_e,axis=0)
|
||||
|
||||
return veq
|
100
cs457-gc/assignment_1_3/src/geometry.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import numpy as np
|
||||
|
||||
def compute_faces_area(V, F):
|
||||
"""
|
||||
Computes the area of the faces of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- area : np.array (|F|,)
|
||||
The area of the faces. The i-th position contains the area of the i-th
|
||||
face.
|
||||
"""
|
||||
|
||||
# HW.1.3.3
|
||||
return np.linalg.norm(np.cross(V[F[:,1]] - V[F[:,0]],V[F[:,2]] - V[F[:,0]], axis=1), axis=1)/2.0
|
||||
|
||||
|
||||
def compute_mesh_area(V, F):
|
||||
"""
|
||||
Computes the area of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- area : float
|
||||
The area of the mesh.
|
||||
"""
|
||||
|
||||
# HW.1.3.3
|
||||
return np.sum(compute_faces_area(V,F))
|
||||
|
||||
|
||||
def compute_faces_centroid(V, F):
|
||||
"""
|
||||
Computes the area centroid of each face of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- cf : np.array (|F|, 3)
|
||||
The area centroid of the faces.
|
||||
"""
|
||||
|
||||
# HW.1.3.4
|
||||
return (V[F[:,0]]+ V[F[:,1]] + V[F[:,2]])/3.0
|
||||
|
||||
|
||||
def compute_mesh_centroid(V, F):
|
||||
"""
|
||||
Computes the area centroid of a given triangle mesh (V, F).
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (|F|, 3)
|
||||
The array of triangle faces.
|
||||
Output:
|
||||
- centroid : np.array (3,)
|
||||
The area centroid of the mesh.
|
||||
"""
|
||||
|
||||
# HW.1.3.4
|
||||
face_centroid = compute_faces_centroid(V,F)
|
||||
face_area = compute_faces_area(V,F)
|
||||
return 1.0/np.sum(face_area) * np.sum(np.einsum('i,ij->ij', face_area, face_centroid), axis=0)
|
||||
|
||||
|
||||
def compute_center_support_line(V):
|
||||
"""
|
||||
Computes the x coordinate of the center of the support line
|
||||
|
||||
Input:
|
||||
- V : np.array (|V|, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
|
||||
Output:
|
||||
- x_csl : float
|
||||
the x coordinate of the center of the support line
|
||||
"""
|
||||
|
||||
# HW.1.3.5
|
||||
support_v = np.fromiter((v[0] for v in V if v[1]<10**-5), dtype=V.dtype)
|
||||
x_csl = np.amin(support_v)+(np.amax(support_v)-np.amin(support_v))/2
|
||||
|
||||
return x_csl
|
173
cs457-gc/assignment_1_3/src/linesearch.py
Normal file
@@ -0,0 +1,173 @@
|
||||
from energies import *
|
||||
from optimization import compute_optimization_objective, compute_optimization_objective_gradient
|
||||
import numpy as np
|
||||
import time
|
||||
import igl
|
||||
|
||||
def evaluate_armijo_rule(f_x, f_x1, p, grad, c, alpha):
|
||||
"""
|
||||
Check the armijo rule, return true if the armijo condition is satisfied
|
||||
|
||||
Input:
|
||||
- f_x : float
|
||||
The function value at x
|
||||
- f_x1 : float
|
||||
The function value at x_(k+1) = x_k + alpha * p_k
|
||||
- p: np.array(2 * #V, 1)
|
||||
The flatten search direction
|
||||
Here, we use the flatten the search direction.
|
||||
The flatten process asks the all x coordinates to be first
|
||||
then all y cooridnates to be the second.
|
||||
- grad: np.array(2 * #V, 1)
|
||||
The gradient of the function at x
|
||||
Here, we use the flatten the gradient
|
||||
The flatten process asks the all x coordinates to be first
|
||||
then all y cooridnates to be the second.
|
||||
- c: float
|
||||
The coefficient for armijo condition
|
||||
- alpha: float
|
||||
The current step size
|
||||
|
||||
Output:
|
||||
- condition: bool
|
||||
True if the armijio condition is satisfied
|
||||
"""
|
||||
return f_x1 <= f_x + c*alpha*np.dot(p.T,grad)
|
||||
|
||||
def backtracking_line_search(p, grad, x, theta, beta, c, f, *arg):
|
||||
"""
|
||||
Computes the step size for p that satisfies the armijio condition.
|
||||
|
||||
Input:
|
||||
- p: np.array(2 * #V, 1)
|
||||
The flatten search direction
|
||||
Here, we use the flatten the search direction.
|
||||
The flatten process asks the all x coordinates to be first
|
||||
then all y cooridnates to be the second.
|
||||
- grad: np.array(2 * #V, 1)
|
||||
The gradient of the function at x
|
||||
Here, we use the flatten the gradient
|
||||
The flatten process asks the all x coordinates to be first
|
||||
then all y cooridnates to be the second.
|
||||
- x : np.array(#V * 2, 1)
|
||||
The array of optimization variables
|
||||
x = V[:, 0 : 2].flatten()
|
||||
- theta: float
|
||||
The initial step size
|
||||
- beta : float
|
||||
The backtracking ratio, alpha = beta * alpha
|
||||
- c: float
|
||||
The coefficient for armijo condition
|
||||
- f: function
|
||||
The objective function (i.e., optimization.compute_optimization_objective)
|
||||
- *arg: parameters
|
||||
The rest parameters for the function f except the its first variables Vx
|
||||
|
||||
Output:
|
||||
- alpha: float
|
||||
The step size for p that satisfies the armijio condition
|
||||
"""
|
||||
|
||||
alpha = theta
|
||||
x1 = x + alpha*p
|
||||
while not evaluate_armijo_rule(f(x,*arg),f(x1, *arg), p, grad, c, alpha):
|
||||
alpha = beta*alpha
|
||||
x1 = x+alpha*p
|
||||
|
||||
return alpha
|
||||
|
||||
def gradient_descent_with_line_search(V, F, x_csl, w, obj_tol, theta, beta, c, iter):
|
||||
"""
|
||||
Find equilibrium shape by using gradient descent with backtracking line search
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row.
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
- w : float
|
||||
The weight for shape preservation energy.
|
||||
- obj_tol: float
|
||||
The termination condition for optimization.
|
||||
The program stop running if
|
||||
the absolute difference between the objectives of two consecutive iterations is smaller than obj_tol
|
||||
- theta : float
|
||||
The initial gradient descent step size.
|
||||
- beta : float
|
||||
The backtracking ratio, alpha = beta * alpha
|
||||
- c: float
|
||||
The coefficient for armijo condition.
|
||||
- iter : int
|
||||
The maximum number of iteration for gradient descent.
|
||||
|
||||
Output:
|
||||
- V1 : np.array (#V, 3)
|
||||
The optimized mesh's vertices
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- energy: np.array(iters, 1)
|
||||
The objective function energy curve with respect to the number of iterations.
|
||||
- running_time: float
|
||||
The tot running time of the optimization
|
||||
"""
|
||||
|
||||
V1 = V.copy()
|
||||
|
||||
# this function of libigl returns an array (#edges, 2) where i-th row
|
||||
# contains the indices of the two vertices of i-th edge.
|
||||
E = igl.edges(F)
|
||||
|
||||
fix = np.where(V1[:, 1] < 1e-3)[0]
|
||||
|
||||
L0 = compute_edges_length(V1, E)
|
||||
|
||||
t0 = time.time()
|
||||
|
||||
energy = []
|
||||
|
||||
obj_prev = 0
|
||||
|
||||
it_time = 0
|
||||
|
||||
while(True):
|
||||
|
||||
# energy
|
||||
obj = compute_optimization_objective(V1, F, E, x_csl, L0, w)
|
||||
|
||||
if abs(obj_prev - obj) < obj_tol:
|
||||
break
|
||||
|
||||
if it_time > iter:
|
||||
break
|
||||
|
||||
obj_prev = obj
|
||||
|
||||
energy.append(obj)
|
||||
|
||||
grad = compute_optimization_objective_gradient(V1, F, E, x_csl, L0, w)
|
||||
|
||||
grad[fix] = 0
|
||||
|
||||
### start of your code.
|
||||
gradf = grad.flatten()
|
||||
ff = F.flatten()
|
||||
vf = V[:, 0 : 2].flatten()
|
||||
unflatten = lambda x: np.concatenate((np.reshape(x,(V.shape[0],2)),np.zeros((V.shape[0],1))),axis=-1)
|
||||
|
||||
f = lambda x: compute_optimization_objective(unflatten(x), F, E, x_csl, L0, w)
|
||||
alpha = backtracking_line_search(-gradf, gradf, vf, theta, beta, c, f)
|
||||
x_cm = compute_mesh_centroid(V, F)[0]
|
||||
|
||||
grad_f = np.zeros((np.shape(grad)[0],3))
|
||||
grad_f[:,:-1] = grad
|
||||
V1 = V1 -(alpha * grad_f)
|
||||
### end of your code.
|
||||
|
||||
it_time = it_time + 1
|
||||
|
||||
running_time = time.time() - t0
|
||||
|
||||
return [V1, F, energy, running_time]
|
137
cs457-gc/assignment_1_3/src/optimization.py
Normal file
@@ -0,0 +1,137 @@
|
||||
from energies import compute_edges_length
|
||||
from energies import compute_equilibrium_energy_gradient, compute_equilibrium_energy
|
||||
from energies import compute_shape_energy_gradient, compute_shape_energy
|
||||
from geometry import compute_mesh_centroid
|
||||
import numpy as np
|
||||
import time
|
||||
import igl
|
||||
|
||||
def compute_optimization_objective(V, F, E, x_csl, L0, w):
|
||||
"""
|
||||
Compute the objective function of make-it-stand problem.
|
||||
E = E_equilibrium + w * E_shape
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- E : np.array (#edges, 2)
|
||||
The array of mesh edges.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
- L0 : np.array (#edges,)
|
||||
The rest lengths of mesh edges.
|
||||
- w : float
|
||||
The weight for shape preservation energy.
|
||||
Output:
|
||||
- obj : float
|
||||
The value of the objective function.
|
||||
"""
|
||||
|
||||
E_eq = compute_equilibrium_energy(V, F, x_csl)
|
||||
E_sh = compute_shape_energy(V, E, L0)
|
||||
obj = E_eq + w*E_sh
|
||||
|
||||
return obj
|
||||
|
||||
def compute_optimization_objective_gradient(V, F, E, x_csl, L0, w):
|
||||
"""
|
||||
Compute the gradient of the objective function of make-it-stand problem.
|
||||
D_E = D_E_equilibrium + w * D_E_shape
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- E : np.array (#edges, 2)
|
||||
The array of mesh edges.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
- l0 : np.array (#edges,)
|
||||
The rest lengths of mesh edges.
|
||||
- w : float
|
||||
The weight for shape preservation energy.
|
||||
Output:
|
||||
- grad_obj : np.array (#V, 2)
|
||||
The gradient of objective function.
|
||||
"""
|
||||
|
||||
grad_E_eq = compute_equilibrium_energy_gradient(V, F, x_csl)
|
||||
grad_E_sh = compute_shape_energy_gradient(V, E, L0)
|
||||
grad_obj = grad_E_eq + w * grad_E_sh
|
||||
|
||||
return grad_obj
|
||||
|
||||
def fixed_step_gradient_descent(V, F, x_csl, w, theta, iters):
|
||||
"""
|
||||
Find equilibrium shape by using fixed step gradient descent method
|
||||
|
||||
Input:
|
||||
- V : np.array (#V, 3)
|
||||
The array of vertices positions.
|
||||
Contains the coordinates of the i-th vertex in i-th row
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- x_csl : float
|
||||
The x coordinate of the center of the support line.
|
||||
- w : float
|
||||
The weight for shape preservation energy.
|
||||
- theta : float
|
||||
The optimization step.
|
||||
- iters : int
|
||||
The number of iteration for gradient descent.
|
||||
|
||||
Output:
|
||||
- V1 : np.array (#V, 3)
|
||||
The optimized mesh's vertices
|
||||
- F : np.array (#F, 3)
|
||||
The array of triangle faces.
|
||||
- energy: np.array(iters, 1)
|
||||
The objective function energy curve with respect to the number of iterations.
|
||||
- running_time: float
|
||||
The tot running time of the optimization
|
||||
"""
|
||||
|
||||
V1 = V.copy()
|
||||
|
||||
# this function of libigl returns an array (#edges, 2) where i-th row
|
||||
# contains the indices of the two vertices of i-th edge.
|
||||
E = igl.edges(F)
|
||||
|
||||
fix = np.where(V1[:, 1] < 1e-3)[0]
|
||||
|
||||
L0 = compute_edges_length(V1, E)
|
||||
|
||||
t0 = time.time()
|
||||
|
||||
energy = []
|
||||
|
||||
for i in range(iters):
|
||||
|
||||
grad = compute_optimization_objective_gradient(V1, F, E, x_csl, L0, w)
|
||||
|
||||
obj = compute_optimization_objective(V1, F, E, x_csl, L0, w)
|
||||
|
||||
energy.append(obj)
|
||||
|
||||
grad[fix] = 0
|
||||
|
||||
### start of your code.
|
||||
x_cm = compute_mesh_centroid(V, F)[0]
|
||||
if abs(x_csl - x_cm)<=10**-3:
|
||||
break
|
||||
if (np.linalg.norm(grad)<=10**-3):
|
||||
break
|
||||
|
||||
grad_f = np.zeros((np.shape(grad)[0],3))
|
||||
grad_f[:,:-1] = grad
|
||||
V1 = V1 -(theta * grad_f)
|
||||
### end of your code.
|
||||
|
||||
running_time = time.time() - t0
|
||||
|
||||
return [V1, F, energy, running_time]
|
45
cs457-gc/assignment_1_3/src/utility.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
import triangle as tr
|
||||
|
||||
def triangulate_mesh(Ps, Holes, area_density):
|
||||
'''
|
||||
Triangulates a set of points given by P using Delaunay scheme
|
||||
|
||||
Input:
|
||||
- P : list of N lists of 2 elements giving the vertices positions
|
||||
- Holes: list of M lists of 2 elements giving the holes positions
|
||||
- area_density: the maximum triangle area
|
||||
|
||||
Output:
|
||||
- V : array of shape (nNodes, 3) containing the vertices position
|
||||
- F : array of vertices ids (list of length nTri of lists of length 3). The ids are such that the algebraic area of
|
||||
each triangle is positively oriented
|
||||
'''
|
||||
|
||||
num_points = 0
|
||||
points = []
|
||||
segments = []
|
||||
for k, _ in enumerate(Ps):
|
||||
P = np.array(Ps[k])
|
||||
N = P.shape[0]
|
||||
points.append(P)
|
||||
index = np.arange(N)
|
||||
seg = np.stack([index, index + 1], axis=1) % N + num_points
|
||||
segments.append(seg)
|
||||
num_points += N
|
||||
|
||||
points = np.vstack(points)
|
||||
segments = np.vstack(segments)
|
||||
|
||||
data = []
|
||||
if Holes == [] or Holes == [[]] or Holes == None:
|
||||
data = dict(vertices=points, segments=segments)
|
||||
else:
|
||||
data = dict(vertices=points, segments=segments, holes = Holes)
|
||||
|
||||
tri = tr.triangulate(data, 'qpa{}'.format(area_density))
|
||||
|
||||
V = np.array([[v[0], v[1], 0] for v in tri["vertices"]])
|
||||
F = np.array([[f[0], f[1], f[2]] for f in tri["triangles"]])
|
||||
return [V, F]
|
67
cs457-gc/assignment_1_3/test/test3.py
Normal file
@@ -0,0 +1,67 @@
|
||||
# import pytest
|
||||
import time
|
||||
import pytest
|
||||
import json
|
||||
import sys
|
||||
import igl
|
||||
import numpy as np
|
||||
sys.path.append('../')
|
||||
sys.path.append('../src')
|
||||
from src.energies import *
|
||||
from src.linesearch import *
|
||||
from src.bfgs import *
|
||||
eps = 1E-6
|
||||
|
||||
with open('test_data3.json', 'r') as infile:
|
||||
homework_datas = json.load(infile)
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[0])
|
||||
def test_armijo_rule(data):
|
||||
Fx = data[0]
|
||||
Fy = data[1]
|
||||
p = np.array(data[2], dtype=float)
|
||||
grad = np.array(data[3], dtype=float)
|
||||
c = data[4]
|
||||
alpha = data[5]
|
||||
armijo_rule_ground_truth = data[6]
|
||||
armijo_rule_student = int(evaluate_armijo_rule(Fx, Fy, p, grad, c, alpha))
|
||||
assert armijo_rule_ground_truth == armijo_rule_student
|
||||
|
||||
def func(x):
|
||||
return np.linalg.norm(x) ** 2
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[1])
|
||||
def test_backtracking_line_search(data):
|
||||
p = np.array(data[0], dtype=float)
|
||||
grad = np.array(data[1], dtype=float)
|
||||
x = np.array(data[2], dtype=float)
|
||||
theta = data[3]
|
||||
beta = data[4]
|
||||
c = data[5]
|
||||
backtracking_line_search_ground_truth = data[6]
|
||||
backtracking_line_search_student = backtracking_line_search(p, grad, x, theta, beta, c, func)
|
||||
|
||||
assert np.linalg.norm(backtracking_line_search_ground_truth - backtracking_line_search_student) < eps
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[2])
|
||||
def test_compute_approximate_hessian_matrix(data):
|
||||
sk = np.array(data[0], dtype=float)
|
||||
yk = np.array(data[1], dtype=float)
|
||||
Bk = np.array(data[2], dtype=float)
|
||||
|
||||
newBk_student = compute_approximate_hessian_matrix(sk, yk, Bk)
|
||||
newBk_ground_truth = np.array(data[3], dtype=float)
|
||||
assert np.linalg.norm(newBk_student - newBk_ground_truth) < eps
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.parametrize("data", homework_datas[3])
|
||||
def test_compute_inverse_approximate_hessian_matrix(data):
|
||||
sk = np.array(data[0], dtype=float)
|
||||
yk = np.array(data[1], dtype=float)
|
||||
invBk = np.array(data[2], dtype=float)
|
||||
inv_newBk_student = compute_inverse_approximate_hessian_matrix(sk, yk, invBk)
|
||||
inv_newBk_ground_truth = np.array(data[3], dtype=float)
|
||||
assert np.linalg.norm(inv_newBk_student - inv_newBk_ground_truth) < eps
|
1
cs457-gc/assignment_1_3/test/test_data3.json
Normal file
@@ -0,0 +1 @@
|
||||
[[[2.0000000000000004, 2.0000000000000004, [-2, -2], [2, 2], 0.5, 1.0, 0], [2.0000000000000004, 0.0, [-2, -2], [2, 2], 0.5, 0.5, 1]], [[[-2, -2], [2, 2], [1, 1], 2.1, 0.5, 0.5, 0.2625]], [[[[-2.0], [-2.0]], [[-4.0], [-4.0]], [[1.0, 0.0], [0.0, 1.0]], [[1.5, 0.5], [0.5, 1.5]]]], [[[[-2.0], [-2.0]], [[-4.0], [-4.0]], [[1.0, 0.0], [0.0, 1.0]], [[0.75, -0.25], [-0.25, 0.75]]]]]
|
834
cs457-gc/assignment_2_1/data/ball.obj
Normal file
@@ -0,0 +1,834 @@
|
||||
v 3.06161699786838e-17 -7.49879891330929e-33 0.5
|
||||
v 3.06161699786838e-17 -7.49879891330929e-33 -0.5
|
||||
v 0.154508497187474 -3.78436673043416e-17 -0.475528258147577
|
||||
v 0.293892626146237 -7.19829327805997e-17 -0.404508497187474
|
||||
v 0.404508497187474 -9.90760072617093e-17 -0.293892626146236
|
||||
v 0.475528258147577 -1.16470831848909e-16 -0.154508497187473
|
||||
v 0.5 -1.22464679914735e-16 7.6571373978539e-16
|
||||
v 0.475528258147577 -1.16470831848909e-16 0.154508497187474
|
||||
v 0.404508497187474 -9.90760072617092e-17 0.293892626146237
|
||||
v 0.293892626146237 -7.19829327805998e-17 0.404508497187473
|
||||
v 0.154508497187475 -3.78436673043417e-17 0.475528258147576
|
||||
v 0.21857645514496 0.136716465258129 0.428407447861946
|
||||
v 0.475945187701446 -0.132880263668928 0.0762824608354488
|
||||
v 0.218576349120797 -0.134908613951094 -0.428980239040003
|
||||
v 0.228603425820446 -0.140038091834834 0.422054269660211
|
||||
v 0.437104447096958 0.151793486569612 0.189468835862535
|
||||
v 0.42898023903994 0.134908613950884 -0.21857634912105
|
||||
v 0.428980239039898 -0.134908613951062 -0.218576349121023
|
||||
v 0.218576349121032 0.134908613951053 -0.428980239039896
|
||||
v 0.340440645253916 0.134908613951044 0.34044064525392
|
||||
v 0.476615030125843 -0.131924241455095 -0.0737163996315581
|
||||
v 0.407622547196207 -0.259520994885 -0.128423955051913
|
||||
v 0.338436818269637 -0.252043139096244 -0.26820659215246
|
||||
v 0.340989631871085 -0.116746524471516 -0.34654915954341
|
||||
v 0.075316277025205 -0.134908613951047 0.475528258147578
|
||||
v 0.0753162770252058 0.134908613951052 -0.475528258147577
|
||||
v 0.337051887252752 0.13152434625125 -0.345104870499591
|
||||
v 0.342307229899869 0.259749321291958 -0.255648294433281
|
||||
v 0.235302886190634 0.257758938760451 0.358040334654413
|
||||
v 0.0930553185121102 0.241091096498632 0.428037137273972
|
||||
v 0.414887348894352 0.253233345682864 -0.117223548665273
|
||||
v 0.309219636002729 0.365205559163796 -0.144941768535501
|
||||
v 0.116382730487621 0.357335962703667 0.329797013029059
|
||||
v 0.220295554503833 0.356044147287606 -0.273317459830304
|
||||
v 0.173924737961772 0.443407381211481 -0.152118637293744
|
||||
v 0.0757439138278267 0.415836842579461 -0.2671003179923
|
||||
v 0.0224933467184133 0.480041055177656 -0.138038526134294
|
||||
v 0.248065266401332 0.358015947011543 0.245536566096914
|
||||
v 0.138163331821839 0.43047956133561 0.21353744639334
|
||||
v 0.360552014587397 0.346405942121308 -0.00227333235984791
|
||||
v 0.123093945281709 0.484207258358844 -0.0197790694319915
|
||||
v -0.0375624502146155 0.498585389330104 0.0012930121510933
|
||||
v -0.0319756224028659 0.329253812136088 0.374925975048146
|
||||
v -0.0571707300985015 0.188277472409031 0.459655415505214
|
||||
v 0.44634465869394 0.222444950782125 0.0359817943817138
|
||||
v 0.114071738612042 0.30750614917439 -0.377395822274126
|
||||
v 0.236387555749274 0.430565411758525 0.0934577427723124
|
||||
v 0.378115930351658 0.292151103254715 0.147227973161872
|
||||
v 0.0698331513994325 -0.131524346251195 -0.477309833660296
|
||||
v -0.0276507157238025 0.368077837732622 -0.337274581446689
|
||||
v -0.132019323454869 0.46789161623721 -0.116826083086996
|
||||
v -0.178527337205295 0.268217150323689 0.382344805303572
|
||||
v -0.195982573985885 0.117715178528912 0.444672876885665
|
||||
v -0.188769871137012 0.462097824846099 0.0288363663352296
|
||||
v -0.311118332326446 0.185953595932789 0.344422187801651
|
||||
v 0.298513275017753 -0.364576673892107 -0.167253321318123
|
||||
v -0.27446477920923 0.408828269442573 -0.0867671082739308
|
||||
v -0.321076581736832 0.0337877006396921 0.381796044958135
|
||||
v -0.406068994209582 0.0890512487956863 0.27780901178606
|
||||
v -0.396337226815336 -0.0658166787739775 0.297632268807486
|
||||
v 0.137344602759695 -0.267387515925555 0.399550217644719
|
||||
v -0.469353412437567 -0.00745235730436951 0.172197086513736
|
||||
v -0.438850244007533 -0.16046355744979 0.17793793880195
|
||||
v -0.488260481987745 -0.0978280168539874 0.0450708425427184
|
||||
v -0.433483128474169 -0.244453321072111 0.0483213321946162
|
||||
v -0.460620100758965 -0.173287974513347 -0.0883198769579221
|
||||
v -0.383511806626786 -0.309356779000242 -0.08495338406711
|
||||
v -0.336717499334961 -0.365993326701377 0.0516740791080927
|
||||
v -0.267862281691792 -0.414575366652434 -0.0798565176542698
|
||||
v -0.205085219904653 -0.452251021719178 0.0583872069088724
|
||||
v -0.389473197418456 -0.226083984285031 -0.217247924138414
|
||||
v -0.445256364809781 -0.0799966822341631 -0.212949055945092
|
||||
v -0.00351125947165275 -0.267035886479874 0.422704987418922
|
||||
v -0.353169743739217 -0.125114465368412 -0.331085340452809
|
||||
v -0.38892388844103 0.0261181792321889 -0.313139026174485
|
||||
v -0.278756909608118 -0.262391732725563 -0.321628922740179
|
||||
v -0.249429844449192 -0.39750217428021 0.172559480007787
|
||||
v -0.125203314206269 -0.478452051724907 -0.0735375027587528
|
||||
v -0.0528582364531956 -0.493487744300911 0.0606288138087549
|
||||
v 0.271731582933658 -0.249600298700644 0.337433901267964
|
||||
v -0.495847117939593 0.0542719818547096 0.034499095880349
|
||||
v 0.341636271151409 -0.364235836672196 -0.0248377438078891
|
||||
v -0.278221380393658 -0.0165162196036634 -0.415114535979952
|
||||
v -0.385894465893779 0.231366911979078 0.218070661102819
|
||||
v 0.129422773211733 -0.26368230955868 -0.404624993543385
|
||||
v 0.17079787798835 -0.360453290963367 0.301498772648173
|
||||
v -0.2972397651044 0.134475553784439 -0.378899521608367
|
||||
v -0.390729424978202 0.17308135749756 -0.259563788196669
|
||||
v 0.0302401087170613 -0.494617483324727 -0.0666264287973931
|
||||
v -0.0447104151313644 -0.455911463185833 -0.200363960118914
|
||||
v -0.289781305004565 -0.107480642258869 0.393032704503674
|
||||
v -0.28072748874216 0.276043192337753 -0.308208100199367
|
||||
v 0.106085899784673 -0.483055958177403 0.0735032185430484
|
||||
v -0.143288452953271 0.380504725979635 0.291006138693707
|
||||
v -0.0207720062787277 -0.262149359393134 -0.425260199319106
|
||||
v -0.0793282266177742 -0.112493174960849 0.480679017691543
|
||||
v -0.210229488803243 0.104747954203238 -0.441397131988602
|
||||
v 0.435024352571936 -0.127806035969131 0.210759174982314
|
||||
v 0.298839864283654 -0.34288662805342 0.207661974894498
|
||||
v -0.343961566185834 -0.213169748618088 0.293681969588004
|
||||
v -0.217656630917657 -0.259665634918282 0.367694641054313
|
||||
v -0.318981501523703 0.381763369474201 0.0500752574969736
|
||||
v -0.395445063483211 0.303503289973959 -0.0388452666581461
|
||||
v 0.00695685172784659 -0.466794760772503 0.179037017204205
|
||||
v -0.141786434074944 -0.0639250457860653 -0.475194902785753
|
||||
v 0.123376202006679 -0.445805073774975 -0.189831896621448
|
||||
v 0.0273264572598231 -0.36207385125428 -0.343737968475292
|
||||
v -0.179178868825853 0.231344360320625 -0.40543152308883
|
||||
v -0.131442519100517 -0.37228536331636 -0.30680037880178
|
||||
v 0.213344976802497 -0.44944368426887 -0.0498427080320272
|
||||
v -0.095411435088729 0.468568967697982 0.146081417588813
|
||||
v 0.19556911033449 -0.349389679263868 -0.299465482329545
|
||||
v -0.212579734450761 0.392914303643436 -0.22456225527287
|
||||
v 0.00442729082563762 0.431790532829453 0.252066131907487
|
||||
v 0.251435921428911 -0.424020659066107 0.0835850351458869
|
||||
v -0.0716881267417996 0.0362403081699758 0.493505271043782
|
||||
v 0.409702957808806 -0.250532734704164 0.139200701163351
|
||||
v 0.354048851093961 -0.123591021755264 0.33071841554491
|
||||
v -0.409329654955812 0.269763307055223 0.0983717019288848
|
||||
v -0.23775056881332 0.409432492346691 0.160747321096556
|
||||
v -0.280167779637764 0.310303261210272 0.274258821799984
|
||||
v 0.0390199999029228 -0.340176969429353 0.364358434892671
|
||||
v -0.106955495739533 -0.389774683020182 0.294340310538035
|
||||
v -0.125152025350624 -0.457070129870627 0.159448634144933
|
||||
v 0.250205349609497 0.430527105380925 -0.0452072401182732
|
||||
v -0.15862733630032 -0.0449406159687499 0.472035707563119
|
||||
v -0.372118237460504 -0.283526014116421 0.176468174662014
|
||||
v -0.235245742246689 -0.152187819676347 -0.41412354231191
|
||||
v 0.479986141812706 0.124680814448665 -0.063780860578784
|
||||
v -0.0761042573074939 0.431963531953512 -0.240032600039915
|
||||
v -0.288453021308633 -0.353652776154199 -0.204265925734934
|
||||
v -0.458840137015611 0.057463941494015 -0.190167358112447
|
||||
v -0.444083105517519 0.194920415588484 -0.121639742603844
|
||||
v -0.178055249060845 -0.43316536366806 -0.175111667230364
|
||||
v -0.491963173165518 -0.0298523928793253 -0.0841490991531884
|
||||
v -0.45636138284715 0.138396610027018 0.150268648023688
|
||||
v -0.345904715972311 0.313415014736247 -0.179223201639723
|
||||
v -0.153169726530236 -0.269052072762942 -0.392619430258638
|
||||
v -0.0419923946510265 0.170189522618945 -0.468265058681734
|
||||
v 0.243612070418092 0.241981955824921 -0.363452737232445
|
||||
v 0.338867576345089 0.252678472264692 0.2670624559087
|
||||
v 0.426863022631355 -0.25994025908482 0.0147993789376581
|
||||
v 0.158342102182598 -0.434609327079221 0.18984865417522
|
||||
v 0.0452931243905481 0.0952764475019849 0.488744239285072
|
||||
v -0.237259629761916 0.0166159415076913 0.439808797744033
|
||||
v 0.247175666187241 -0.238473344419651 -0.363365730423495
|
||||
v 0.0577997827759178 0.48434516267528 0.10985876616872
|
||||
v -0.334770924239934 0.332574086299653 0.165296416795679
|
||||
v -0.153183582101622 0.339412359720881 -0.333667559470828
|
||||
v 0.36785960116632 -0.228792320684729 0.249666553277471
|
||||
v 0.483390586525237 0.102332156736947 0.0765615475049495
|
||||
v 0.139648641361451 0.213951152339616 -0.429794324507027
|
||||
v -0.0358864034291634 0.302032201639968 -0.396848478920397
|
||||
v -0.180786711862885 -0.175443810495746 0.431897712627121
|
||||
v 0.348215026659532 -0.346723777603642 0.0923521372398145
|
||||
v -0.114480413553308 -0.290654614949134 0.390402522688358
|
||||
v -0.272442803422386 -0.321472772094441 0.269128548588341
|
||||
v -0.466114498296331 0.180818120755528 0.00648703972541844
|
||||
v -0.129415184584831 -0.203585571998795 -0.437955048918034
|
||||
v 0.0643376427947934 -0.412575814735467 0.275030661590622
|
||||
v -0.485934856252322 0.0906364933467189 -0.0751820560562512
|
||||
v -2.77555756156289e-16 3.19189119579733e-16 -1.2490009027033e-16
|
||||
v -0.251828742757562 0.0139490906784806 -0.0181338406388946
|
||||
v 0.197996662720562 -0.0791211777945037 0.136432807235424
|
||||
v 0.125255777218953 0.210831018463626 -0.063969097850248
|
||||
v -0.139628236563409 -0.21265335644906 0.00545121255949739
|
||||
v -0.145223690886062 0.189924594351579 0.11159305462841
|
||||
v -0.112897563504534 -0.0373976158431084 -0.223966661594476
|
||||
v 0.225528258147577 -0.0232431701377701 -0.114912387106339
|
||||
v -0.118530098445147 -0.0689806932344922 0.2117841676383
|
||||
v 0.098269738040353 0.147959392484917 0.178021817259433
|
||||
v 0.100852235573853 -0.219450649709681 -0.0387973024559412
|
||||
v -0.100480207820675 0.192284757140571 -0.148991345058649
|
||||
v 0.08807336311451 0.0516996280513727 -0.271061939721184
|
||||
v 0.272113071694785 0.101244013250397 0.0512575837900759
|
||||
v 0.0341720627218518 -0.221571915156144 0.170600381517002
|
||||
v 0.113793744063312 -0.150466918879953 -0.232830800332848
|
||||
v 0.068592399702004 -0.0245878691620408 0.288679790541826
|
||||
v -0.0741210186337665 0.111594614690448 0.278407708187608
|
||||
v -0.0351094203418499 0.30351870487887 -0.00261521319733849
|
||||
v -0.258447343925187 0.0495111872633636 0.167086499211952
|
||||
v -0.271439309774019 -0.125349807194904 0.104052998028547
|
||||
v -0.0485204373172835 -0.250891695571267 -0.169649174254392
|
||||
v -0.245408905954284 -0.137064807392418 -0.132337064396614
|
||||
v -0.247561324014027 0.19563057757812 -0.0400712992459122
|
||||
v -0.245489451032576 0.0855397985783712 -0.187709278356085
|
||||
v 0.27254656245515 -0.16399276001755 -0.00766125806031415
|
||||
v 0.273716986928946 0.149504817170547 -0.136480234333616
|
||||
v 0.0525334922800396 0.245214764318482 -0.222591039627852
|
||||
v -0.025453222260026 0.265072731295802 0.212780231418037
|
||||
v 0.10188342337719 0.303246953287615 0.102540160700209
|
||||
v -0.14157478784597 -0.241776139413833 0.180194715613577
|
||||
v -0.0121617817639016 -0.325829668630181 0.0394634260162139
|
||||
v 0.222619980200421 0.0438990087026778 0.254181668630204
|
||||
v 0.187862004819913 -0.26556009247797 0.101876795667186
|
||||
v 0.342239361396159 -0.0424148965243595 0.0738730045314498
|
||||
v -0.120466338945889 0.114580505991094 -0.297963959751455
|
||||
v 0.15154406307463 -0.163641254596307 0.268108582070898
|
||||
f 166 170 163 182
|
||||
f 165 162 171 180
|
||||
f 167 171 162 180
|
||||
f 4 5 27 169
|
||||
f 163 166 162 170
|
||||
f 4 24 169 177
|
||||
f 167 173 163 185
|
||||
f 162 163 167 173
|
||||
f 158 136 181 185
|
||||
f 162 171 170 178
|
||||
f 162 163 170 181
|
||||
f 162 167 163 181
|
||||
f 4 169 27 174
|
||||
f 170 171 162 179
|
||||
f 162 173 165 174
|
||||
f 170 178 171 179
|
||||
f 158 181 163 185
|
||||
f 162 176 164 178
|
||||
f 162 170 167 181
|
||||
f 162 170 176 178
|
||||
f 162 166 163 184
|
||||
f 167 170 162 179
|
||||
f 129 169 6 196
|
||||
f 162 165 169 174
|
||||
f 73 176 170 178
|
||||
f 119 181 136 185
|
||||
f 4 169 174 177
|
||||
f 72 132 135 163
|
||||
f 27 174 169 188
|
||||
f 158 119 136 185
|
||||
f 64 66 163 182
|
||||
f 167 162 171 179
|
||||
f 66 135 64 163
|
||||
f 7 129 6 196
|
||||
f 162 173 167 180
|
||||
f 95 177 168 183
|
||||
f 162 177 172 183
|
||||
f 4 24 5 169
|
||||
f 27 169 5 188
|
||||
f 162 169 165 175
|
||||
f 162 164 169 175
|
||||
f 129 175 169 196
|
||||
f 168 177 162 183
|
||||
f 132 161 135 163
|
||||
f 119 148 84 167
|
||||
f 162 165 173 180
|
||||
f 164 162 171 175
|
||||
f 165 171 162 175
|
||||
f 158 81 161 163
|
||||
f 30 171 178 179
|
||||
f 64 81 62 163
|
||||
f 169 162 174 177
|
||||
f 66 163 182 184
|
||||
f 169 177 23 187
|
||||
f 162 170 166 176
|
||||
f 54 167 102 185
|
||||
f 68 166 67 182
|
||||
f 162 168 163 173
|
||||
f 164 171 162 178
|
||||
f 161 158 163 185
|
||||
f 65 68 67 182
|
||||
f 166 168 162 183
|
||||
f 129 6 169 188
|
||||
f 162 163 168 184
|
||||
f 165 175 40 191
|
||||
f 129 169 175 188
|
||||
f 119 167 84 181
|
||||
f 62 64 163 182
|
||||
f 18 169 23 187
|
||||
f 67 182 166 184
|
||||
f 162 168 166 184
|
||||
f 168 174 162 177
|
||||
f 164 162 169 172
|
||||
f 167 181 119 185
|
||||
f 126 178 170 179
|
||||
f 72 163 135 184
|
||||
f 72 132 163 186
|
||||
f 54 180 167 185
|
||||
f 62 163 81 181
|
||||
f 162 168 173 174
|
||||
f 66 135 163 184
|
||||
f 165 174 173 189
|
||||
f 38 141 171 191
|
||||
f 140 174 188 189
|
||||
f 161 163 132 186
|
||||
f 24 23 18 169
|
||||
f 62 163 181 182
|
||||
f 65 182 67 184
|
||||
f 166 162 172 183
|
||||
f 140 174 27 188
|
||||
f 162 166 172 176
|
||||
f 4 14 24 177
|
||||
f 23 169 24 177
|
||||
f 169 172 162 177
|
||||
f 163 173 168 186
|
||||
f 60 181 170 182
|
||||
f 119 148 167 185
|
||||
f 57 173 51 180
|
||||
f 72 163 184 186
|
||||
f 41 35 165 180
|
||||
f 41 37 35 180
|
||||
f 141 171 48 175
|
||||
f 56 177 172 187
|
||||
f 135 161 81 163
|
||||
f 95 49 168 177
|
||||
f 102 54 120 167
|
||||
f 34 140 188 189
|
||||
f 176 178 73 198
|
||||
f 162 172 164 176
|
||||
f 141 171 175 194
|
||||
f 60 170 91 182
|
||||
f 130 37 180 189
|
||||
f 56 23 177 187
|
||||
f 22 18 23 187
|
||||
f 121 55 167 179
|
||||
f 6 169 21 196
|
||||
f 60 91 100 182
|
||||
f 12 30 171 178
|
||||
f 65 66 182 184
|
||||
f 91 170 100 182
|
||||
f 164 172 169 187
|
||||
f 116 178 126 179
|
||||
f 125 165 40 191
|
||||
f 69 67 166 184
|
||||
f 96 73 170 178
|
||||
f 113 51 57 173
|
||||
f 57 173 180 185
|
||||
f 136 119 84 181
|
||||
f 84 167 121 181
|
||||
f 83 75 74 186
|
||||
f 134 131 69 183
|
||||
f 167 179 55 181
|
||||
f 130 180 173 189
|
||||
f 145 179 170 181
|
||||
f 48 171 141 191
|
||||
f 48 175 171 191
|
||||
f 102 167 148 185
|
||||
f 64 135 81 163
|
||||
f 30 178 144 179
|
||||
f 57 180 54 185
|
||||
f 121 52 55 179
|
||||
f 40 175 165 188
|
||||
f 60 91 170 181
|
||||
f 130 51 173 180
|
||||
f 76 183 168 184
|
||||
f 74 75 72 184
|
||||
f 140 19 27 174
|
||||
f 165 180 171 191
|
||||
f 49 174 168 177
|
||||
f 83 74 168 186
|
||||
f 84 121 55 181
|
||||
f 69 70 78 166
|
||||
f 120 167 54 180
|
||||
f 121 167 55 181
|
||||
f 148 121 84 167
|
||||
f 74 128 168 184
|
||||
f 131 166 69 183
|
||||
f 156 170 176 192
|
||||
f 74 75 184 186
|
||||
f 67 68 69 166
|
||||
f 65 67 66 184
|
||||
f 117 164 150 196
|
||||
f 96 156 154 170
|
||||
f 98 150 164 196
|
||||
f 145 170 58 181
|
||||
f 161 133 158 185
|
||||
f 24 18 5 169
|
||||
f 78 183 166 193
|
||||
f 34 32 165 188
|
||||
f 98 117 150 196
|
||||
f 41 35 125 165
|
||||
f 35 34 32 165
|
||||
f 73 156 170 176
|
||||
f 74 184 168 186
|
||||
f 72 184 75 186
|
||||
f 133 161 132 186
|
||||
f 119 102 148 185
|
||||
f 150 164 117 195
|
||||
f 34 188 165 189
|
||||
f 57 54 102 185
|
||||
f 148 102 120 167
|
||||
f 170 181 163 182
|
||||
f 12 178 171 194
|
||||
f 6 18 21 169
|
||||
f 5 169 6 188
|
||||
f 136 62 81 181
|
||||
f 171 180 167 190
|
||||
f 58 170 91 181
|
||||
f 78 166 70 193
|
||||
f 2 168 49 174
|
||||
f 34 140 28 188
|
||||
f 40 125 32 165
|
||||
f 38 48 141 191
|
||||
f 169 174 165 188
|
||||
f 40 175 48 191
|
||||
f 113 130 51 173
|
||||
f 66 72 135 184
|
||||
f 169 187 21 196
|
||||
f 131 166 183 184
|
||||
f 74 128 83 168
|
||||
f 18 21 169 187
|
||||
f 7 6 21 196
|
||||
f 64 65 66 182
|
||||
f 69 166 131 184
|
||||
f 56 112 172 177
|
||||
f 76 168 128 184
|
||||
f 166 182 68 192
|
||||
f 159 95 168 183
|
||||
f 34 165 35 189
|
||||
f 96 170 126 178
|
||||
f 172 183 89 193
|
||||
f 150 118 98 164
|
||||
f 172 177 106 183
|
||||
f 168 183 166 184
|
||||
f 111 167 120 180
|
||||
f 17 5 6 188
|
||||
f 30 171 179 190
|
||||
f 130 37 51 180
|
||||
f 40 165 32 188
|
||||
f 100 182 170 192
|
||||
f 112 106 172 177
|
||||
f 74 76 128 184
|
||||
f 170 179 167 181
|
||||
f 32 125 35 165
|
||||
f 41 165 125 191
|
||||
f 113 173 57 185
|
||||
f 2 168 174 197
|
||||
f 18 6 5 169
|
||||
f 167 180 111 190
|
||||
f 126 170 145 179
|
||||
f 12 144 30 178
|
||||
f 91 126 154 170
|
||||
f 69 68 70 166
|
||||
f 4 27 19 174
|
||||
f 137 92 173 186
|
||||
f 25 73 178 198
|
||||
f 29 171 141 194
|
||||
f 60 58 91 181
|
||||
f 120 167 111 190
|
||||
f 111 120 54 180
|
||||
f 150 118 164 198
|
||||
f 30 33 29 171
|
||||
f 69 131 67 184
|
||||
f 95 49 159 168
|
||||
f 68 182 127 192
|
||||
f 117 187 164 196
|
||||
f 166 176 170 192
|
||||
f 33 171 30 190
|
||||
f 57 51 54 180
|
||||
f 137 92 113 173
|
||||
f 22 23 56 187
|
||||
f 37 36 35 189
|
||||
f 29 38 141 171
|
||||
f 150 164 195 198
|
||||
f 180 190 171 191
|
||||
f 145 91 58 170
|
||||
f 41 180 165 191
|
||||
f 82 187 172 195
|
||||
f 137 173 185 186
|
||||
f 113 137 173 185
|
||||
f 112 106 177 183
|
||||
f 164 187 117 195
|
||||
f 154 170 156 192
|
||||
f 148 120 121 167
|
||||
f 165 188 174 189
|
||||
f 76 138 168 183
|
||||
f 116 96 126 178
|
||||
f 76 138 128 168
|
||||
f 82 56 172 187
|
||||
f 172 176 166 193
|
||||
f 9 98 118 164
|
||||
f 30 29 12 171
|
||||
f 70 166 192 193
|
||||
f 33 38 29 171
|
||||
f 165 175 169 188
|
||||
f 96 73 156 170
|
||||
f 141 175 16 194
|
||||
f 96 25 73 178
|
||||
f 45 175 40 188
|
||||
f 98 164 9 196
|
||||
f 121 94 52 190
|
||||
f 106 56 112 172
|
||||
f 70 68 77 166
|
||||
f 70 192 124 193
|
||||
f 169 175 164 196
|
||||
f 31 45 40 188
|
||||
f 172 177 169 187
|
||||
f 106 89 172 183
|
||||
f 113 149 130 173
|
||||
f 149 189 173 197
|
||||
f 121 167 94 190
|
||||
f 171 175 165 191
|
||||
f 93 110 193 195
|
||||
f 172 193 110 195
|
||||
f 125 40 47 191
|
||||
f 3 49 14 177
|
||||
f 96 154 126 170
|
||||
f 78 90 183 193
|
||||
f 152 26 174 189
|
||||
f 113 57 137 185
|
||||
f 16 194 175 196
|
||||
f 60 62 181 182
|
||||
f 110 82 172 195
|
||||
f 92 149 113 173
|
||||
f 146 23 24 177
|
||||
f 34 28 32 188
|
||||
f 163 185 173 186
|
||||
f 72 75 132 186
|
||||
f 91 145 126 170
|
||||
f 38 171 33 191
|
||||
f 124 192 104 193
|
||||
f 18 22 21 187
|
||||
f 77 166 68 192
|
||||
f 130 36 37 189
|
||||
f 30 179 43 190
|
||||
f 131 183 76 184
|
||||
f 89 110 172 193
|
||||
f 121 120 94 167
|
||||
f 9 164 118 194
|
||||
f 173 174 168 197
|
||||
f 12 171 29 194
|
||||
f 56 23 112 177
|
||||
f 116 1 96 178
|
||||
f 17 27 5 188
|
||||
f 140 27 28 188
|
||||
f 104 192 176 193
|
||||
f 120 94 167 190
|
||||
f 112 177 107 183
|
||||
f 82 56 110 172
|
||||
f 169 164 187 196
|
||||
f 164 175 171 194
|
||||
f 118 194 164 198
|
||||
f 3 174 49 177
|
||||
f 9 164 194 196
|
||||
f 70 166 77 192
|
||||
f 167 180 173 185
|
||||
f 146 24 14 177
|
||||
f 30 44 43 179
|
||||
f 101 154 156 192
|
||||
f 152 174 140 189
|
||||
f 166 182 163 184
|
||||
f 92 149 173 197
|
||||
f 171 190 33 191
|
||||
f 60 63 62 182
|
||||
f 45 129 175 188
|
||||
f 163 181 167 185
|
||||
f 150 195 99 198
|
||||
f 167 179 171 190
|
||||
f 143 193 176 195
|
||||
f 164 176 172 195
|
||||
f 171 178 164 194
|
||||
f 164 178 176 198
|
||||
f 9 194 16 196
|
||||
f 129 17 6 188
|
||||
f 78 89 90 193
|
||||
f 10 118 15 194
|
||||
f 10 15 178 194
|
||||
f 150 99 80 198
|
||||
f 83 186 168 197
|
||||
f 111 190 180 191
|
||||
f 77 68 127 192
|
||||
f 127 68 65 182
|
||||
f 118 15 194 198
|
||||
f 10 15 11 178
|
||||
f 19 3 4 174
|
||||
f 9 16 8 196
|
||||
f 45 31 129 188
|
||||
f 30 144 44 179
|
||||
f 149 153 189 197
|
||||
f 40 32 31 188
|
||||
f 159 168 138 183
|
||||
f 124 123 104 192
|
||||
f 89 183 90 193
|
||||
f 104 176 143 193
|
||||
f 62 63 64 182
|
||||
f 137 185 133 186
|
||||
f 178 194 15 198
|
||||
f 47 40 48 191
|
||||
f 89 110 106 172
|
||||
f 75 83 87 186
|
||||
f 123 176 104 192
|
||||
f 105 49 2 168
|
||||
f 107 177 95 183
|
||||
f 87 186 83 197
|
||||
f 173 186 92 197
|
||||
f 73 122 176 198
|
||||
f 159 138 95 183
|
||||
f 149 153 50 189
|
||||
f 112 107 106 183
|
||||
f 137 133 88 186
|
||||
f 120 111 94 190
|
||||
f 110 56 106 172
|
||||
f 93 193 143 195
|
||||
f 170 182 166 192
|
||||
f 173 180 165 189
|
||||
f 10 178 11 194
|
||||
f 114 190 111 191
|
||||
f 52 53 55 179
|
||||
f 173 189 174 197
|
||||
f 139 174 26 189
|
||||
f 19 140 152 174
|
||||
f 116 145 53 179
|
||||
f 36 34 35 189
|
||||
f 100 127 182 192
|
||||
f 116 126 145 179
|
||||
f 134 78 90 183
|
||||
f 112 23 146 177
|
||||
f 89 93 110 193
|
||||
f 115 110 93 195
|
||||
f 63 60 100 182
|
||||
f 159 128 138 168
|
||||
f 11 144 12 178
|
||||
f 46 140 34 189
|
||||
f 168 184 163 186
|
||||
f 16 175 151 196
|
||||
f 106 90 89 183
|
||||
f 76 131 109 183
|
||||
f 41 42 37 180
|
||||
f 2 3 26 174
|
||||
f 143 176 86 195
|
||||
f 70 77 124 192
|
||||
f 137 88 92 186
|
||||
f 16 151 8 196
|
||||
f 73 122 156 176
|
||||
f 3 2 49 174
|
||||
f 150 80 118 198
|
||||
f 155 117 187 195
|
||||
f 160 143 104 176
|
||||
f 84 55 59 181
|
||||
f 25 61 73 198
|
||||
f 33 30 43 190
|
||||
f 166 183 172 193
|
||||
f 105 168 2 197
|
||||
f 107 85 95 177
|
||||
f 150 117 99 195
|
||||
f 79 78 70 193
|
||||
f 141 16 20 194
|
||||
f 16 141 48 175
|
||||
f 111 180 147 191
|
||||
f 45 129 151 175
|
||||
f 86 195 176 198
|
||||
f 156 122 123 176
|
||||
f 122 86 176 198
|
||||
f 11 178 12 194
|
||||
f 29 141 20 194
|
||||
f 92 108 149 197
|
||||
f 156 176 123 192
|
||||
f 82 22 56 187
|
||||
f 160 104 123 176
|
||||
f 95 85 49 177
|
||||
f 48 40 45 175
|
||||
f 84 59 136 181
|
||||
f 51 37 42 180
|
||||
f 105 159 49 168
|
||||
f 13 187 117 196
|
||||
f 43 179 52 190
|
||||
f 139 174 189 197
|
||||
f 134 109 131 183
|
||||
f 160 86 143 176
|
||||
f 96 1 25 178
|
||||
f 114 111 147 191
|
||||
f 59 55 58 181
|
||||
f 19 26 3 174
|
||||
f 99 195 86 198
|
||||
f 110 115 82 195
|
||||
f 155 187 82 195
|
||||
f 60 62 59 181
|
||||
f 71 74 72 184
|
||||
f 25 178 15 198
|
||||
f 158 103 119 185
|
||||
f 152 140 46 189
|
||||
f 175 194 164 196
|
||||
f 43 44 52 179
|
||||
f 164 172 187 195
|
||||
f 59 62 136 181
|
||||
f 100 157 127 192
|
||||
f 93 104 143 193
|
||||
f 15 25 11 178
|
||||
f 59 58 60 181
|
||||
f 73 61 122 198
|
||||
f 99 86 80 198
|
||||
f 54 51 42 180
|
||||
f 102 119 103 185
|
||||
f 67 71 66 184
|
||||
f 71 72 66 184
|
||||
f 39 33 190 191
|
||||
f 64 63 65 182
|
||||
f 152 139 26 189
|
||||
f 160 123 122 176
|
||||
f 39 38 33 191
|
||||
f 132 88 133 186
|
||||
f 21 187 13 196
|
||||
f 92 186 87 197
|
||||
f 124 79 70 193
|
||||
f 2 26 139 174
|
||||
f 76 109 138 183
|
||||
f 114 39 33 190
|
||||
f 38 47 48 191
|
||||
f 117 13 142 187
|
||||
f 142 155 117 187
|
||||
f 153 152 46 189
|
||||
f 25 1 11 178
|
||||
f 41 147 42 180
|
||||
f 42 111 54 180
|
||||
f 98 13 117 196
|
||||
f 122 61 86 198
|
||||
f 105 83 128 168
|
||||
f 176 192 166 193
|
||||
f 107 112 85 177
|
||||
f 122 86 160 176
|
||||
f 41 147 180 191
|
||||
f 76 74 71 184
|
||||
f 13 21 142 187
|
||||
f 2 174 139 197
|
||||
f 131 71 67 184
|
||||
f 85 146 14 177
|
||||
f 142 82 155 187
|
||||
f 36 130 50 189
|
||||
f 97 87 83 197
|
||||
f 87 92 88 186
|
||||
f 41 125 47 191
|
||||
f 42 147 111 180
|
||||
f 83 168 105 197
|
||||
f 155 99 117 195
|
||||
f 155 82 115 195
|
||||
f 45 151 16 175
|
||||
f 57 102 103 185
|
||||
f 49 85 14 177
|
||||
f 158 133 103 185
|
||||
f 39 190 114 191
|
||||
f 44 144 116 179
|
||||
f 115 93 143 195
|
||||
f 8 98 9 196
|
||||
f 1 144 11 178
|
||||
f 63 100 127 182
|
||||
f 168 186 173 197
|
||||
f 146 85 112 177
|
||||
f 139 189 153 197
|
||||
f 108 153 149 197
|
||||
f 52 44 53 179
|
||||
f 32 28 31 188
|
||||
f 44 116 53 179
|
||||
f 108 92 87 197
|
||||
f 21 22 142 187
|
||||
f 176 195 164 198
|
||||
f 90 106 107 183
|
||||
f 10 11 12 194
|
||||
f 138 107 95 183
|
||||
f 82 142 22 187
|
||||
f 28 27 17 188
|
||||
f 7 21 13 196
|
||||
f 131 76 71 184
|
||||
f 100 101 157 192
|
||||
f 176 193 172 195
|
||||
f 20 16 9 194
|
||||
f 152 26 19 174
|
||||
f 88 132 75 186
|
||||
f 164 194 178 198
|
||||
f 129 31 17 188
|
||||
f 57 103 137 185
|
||||
f 127 65 63 182
|
||||
f 159 105 128 168
|
||||
f 139 152 153 189
|
||||
f 138 109 107 183
|
||||
f 137 103 133 185
|
||||
f 79 89 78 193
|
||||
f 94 43 52 190
|
||||
f 16 48 45 175
|
||||
f 25 15 61 198
|
||||
f 36 46 34 189
|
||||
f 12 29 20 194
|
||||
f 75 87 88 186
|
||||
f 77 127 157 192
|
||||
f 9 118 10 194
|
||||
f 111 114 94 190
|
||||
f 97 83 105 197
|
||||
f 99 143 86 195
|
||||
f 80 15 118 198
|
||||
f 8 151 7 196
|
||||
f 124 104 79 193
|
||||
f 134 90 109 183
|
||||
f 39 114 147 191
|
||||
f 33 43 114 190
|
||||
f 79 93 89 193
|
||||
f 77 123 124 192
|
||||
f 36 50 46 189
|
||||
f 79 104 93 193
|
||||
f 31 28 17 188
|
||||
f 97 105 139 197
|
||||
f 61 80 86 198
|
||||
f 139 105 2 197
|
||||
f 109 90 107 183
|
||||
f 8 7 13 196
|
||||
f 143 99 115 195
|
||||
f 98 8 13 196
|
||||
f 47 38 39 191
|
||||
f 41 47 147 191
|
||||
f 153 46 50 189
|
||||
f 157 101 123 192
|
||||
f 94 114 43 190
|
||||
f 115 99 155 195
|
||||
f 157 123 77 192
|
||||
f 12 20 10 194
|
||||
f 156 123 101 192
|
||||
f 61 15 80 198
|
||||
f 20 9 10 194
|
||||
f 47 39 147 191
|
||||
f 97 108 87 197
|
||||
f 139 153 108 197
|
||||
f 139 108 97 197
|
||||
f 181 158 81 136
|
||||
f 181 81 158 163
|
||||
f 69 183 78 134
|
||||
f 78 183 69 166
|
||||
f 185 161 186 163
|
||||
f 185 186 161 133
|
||||
f 180 35 189 37
|
||||
f 180 189 35 165
|
||||
f 179 121 190 167
|
||||
f 179 190 121 52
|
||||
f 177 3 4 14
|
||||
f 177 4 3 174
|
||||
f 55 181 53 58
|
||||
f 55 53 181 179
|
||||
f 145 53 181 58
|
||||
f 145 181 53 179
|
||||
f 100 192 91 101
|
||||
f 100 91 192 170
|
||||
f 154 91 192 101
|
||||
f 154 192 91 170
|
||||
f 196 129 151 7
|
||||
f 196 151 129 175
|
||||
f 189 149 130 50
|
||||
f 189 130 149 173
|
||||
f 116 178 144 1
|
||||
f 116 144 178 179
|
486
cs457-gc/assignment_2_1/data/beam.obj
Normal file
@@ -0,0 +1,486 @@
|
||||
v 0 1 0
|
||||
v 1 1 0
|
||||
v 2 1 0
|
||||
v 3 1 0
|
||||
v 4 1 0
|
||||
v 5 1 0
|
||||
v 6 1 0
|
||||
v 7 1 0
|
||||
v 8 1 0
|
||||
v 9 1 0
|
||||
v 10 1 0
|
||||
v 0 0 0
|
||||
v 1 0 0
|
||||
v 2 0 0
|
||||
v 3 0 0
|
||||
v 4 0 0
|
||||
v 5 0 0
|
||||
v 6 0 0
|
||||
v 7 0 0
|
||||
v 8 0 0
|
||||
v 9 0 0
|
||||
v 10 0 0
|
||||
v 0 1 2
|
||||
v 1 1 2
|
||||
v 2 1 2
|
||||
v 3 1 2
|
||||
v 4 1 2
|
||||
v 5 1 2
|
||||
v 6 1 2
|
||||
v 7 1 2
|
||||
v 8 1 2
|
||||
v 9 1 2
|
||||
v 10 1 2
|
||||
v 0 2 2
|
||||
v 1 2 2
|
||||
v 2 2 2
|
||||
v 3 2 2
|
||||
v 4 2 2
|
||||
v 5 2 2
|
||||
v 6 2 2
|
||||
v 7 2 2
|
||||
v 8 2 2
|
||||
v 9 2 2
|
||||
v 10 2 2
|
||||
v 1 0 1
|
||||
v 2 0 1
|
||||
v 3 0 1
|
||||
v 4 0 1
|
||||
v 5 0 1
|
||||
v 6 0 1
|
||||
v 7 0 1
|
||||
v 8 0 1
|
||||
v 9 0 1
|
||||
v 10 0 1
|
||||
v 0 0 2
|
||||
v 1 0 2
|
||||
v 2 0 2
|
||||
v 3 0 2
|
||||
v 4 0 2
|
||||
v 5 0 2
|
||||
v 6 0 2
|
||||
v 7 0 2
|
||||
v 8 0 2
|
||||
v 9 0 2
|
||||
v 10 0 2
|
||||
v 10 1 1
|
||||
v 10 2 0
|
||||
v 9 2 0
|
||||
v 8 2 0
|
||||
v 7 2 0
|
||||
v 6 2 0
|
||||
v 5 2 0
|
||||
v 4 2 0
|
||||
v 3 2 0
|
||||
v 2 2 0
|
||||
v 1 2 0
|
||||
v 0 2 0
|
||||
v 10 2 1
|
||||
v 9 2 1
|
||||
v 8 2 1
|
||||
v 7 2 1
|
||||
v 6 2 1
|
||||
v 5 2 1
|
||||
v 4 2 1
|
||||
v 3 2 1
|
||||
v 2 2 1
|
||||
v 1 2 1
|
||||
v 0 2 1
|
||||
v 0 1 1
|
||||
v 0 0 1
|
||||
v 2.51022314298935 1.66666666734905 0.333333356706744
|
||||
v 6.5038986868305 1.66666666734905 0.333333348448228
|
||||
v 1.41304168673757 1.66666667779573 0.333333333192237
|
||||
v 4.52815518561683 1.66666664336266 0.333333332650945
|
||||
v 3.53193742824908 1.66666666572512 1.66666665537717
|
||||
v 5.5724872830131 1.66666663994982 0.333333333192237
|
||||
v 7.47453499493164 1.66666666734905 0.333333321950017
|
||||
v 8.58595000182103 1.66666669276468 0.333333332650945
|
||||
v 4.15888962504899 1 1
|
||||
v 7.12019383987445 1 1
|
||||
v 6.5 0.94551796216449 0.567320199509105
|
||||
v 8.92715091673299 1 1
|
||||
v 5.70664055187346 1.0895869039962 1.0895869039962
|
||||
v 7.94522720695394 1.16116000103177 0.838839998968228
|
||||
v 6.98921684566362 1.33897006803824 0.50851934829753
|
||||
v 1.5 1.17677467586179 1.17677467586179
|
||||
v 2.5 1.18050331869877 1.18050331869877
|
||||
v 0.700160914479175 1.29983908552083 1.29983908552083
|
||||
v 2.00321717021229 0.747225966728042 0.747225966728042
|
||||
v 1.96163240573044 1.41876165907376 0.649342721084843
|
||||
v 1.23482454703747 0.659293555195857 0.659293555195857
|
||||
v 4.9379505567614 0.801542900957198 1.1984570990428
|
||||
v 0.914541947157469 1.28019711508133 0.634737483550074
|
||||
v 3.32955775380848 1.21040848022 0.971132809002493
|
||||
v 5.05032123289685 1.285671858205 0.667177322648327
|
||||
v 2.83515918585762 0.687849458381568 0.687849458381568
|
||||
v 0.620146271013575 0.620146271013575 1.04905612878929
|
||||
f 62 31 63 100
|
||||
f 50 29 101 103
|
||||
f 21 9 20 102
|
||||
f 10 98 9 102
|
||||
f 25 46 106 109
|
||||
f 35 24 23 108
|
||||
f 106 110 111 113
|
||||
f 28 83 103 112
|
||||
f 81 97 80 104
|
||||
f 109 106 110 111
|
||||
f 89 55 90 117
|
||||
f 49 6 99 112
|
||||
f 7 8 92 101
|
||||
f 29 100 101 103
|
||||
f 46 14 109 116
|
||||
f 36 25 106 107
|
||||
f 23 89 108 117
|
||||
f 76 3 93 2
|
||||
f 86 87 93 106
|
||||
f 106 107 109 110
|
||||
f 68 11 79 10
|
||||
f 27 59 47 48
|
||||
f 46 25 107 109
|
||||
f 81 97 100 105
|
||||
f 46 57 25 106
|
||||
f 97 9 104 105
|
||||
f 3 4 91 116
|
||||
f 2 13 111 117
|
||||
f 2 111 113 117
|
||||
f 41 100 29 81
|
||||
f 19 8 7 101
|
||||
f 47 46 58 107
|
||||
f 63 52 31 102
|
||||
f 83 103 112 115
|
||||
f 4 74 91 114
|
||||
f 6 99 112 115
|
||||
f 95 26 107 114
|
||||
f 37 84 95 85
|
||||
f 3 91 109 116
|
||||
f 43 66 44 32
|
||||
f 11 68 79 67
|
||||
f 79 11 78 66
|
||||
f 26 57 25 107
|
||||
f 3 75 93 110
|
||||
f 50 29 100 101
|
||||
f 74 86 91 85
|
||||
f 6 72 94 115
|
||||
f 62 63 51 100
|
||||
f 106 86 107 110
|
||||
f 102 21 66 53
|
||||
f 80 31 42 100
|
||||
f 69 10 98 9
|
||||
f 49 6 112 115
|
||||
f 86 36 106 107
|
||||
f 96 7 101 103
|
||||
f 93 86 106 110
|
||||
f 43 102 66 32
|
||||
f 57 46 25 107
|
||||
f 47 58 26 107
|
||||
f 98 97 80 69
|
||||
f 35 87 106 108
|
||||
f 26 37 95 107
|
||||
f 83 72 96 115
|
||||
f 84 5 99 114
|
||||
f 47 46 107 116
|
||||
f 60 61 49 112
|
||||
f 57 26 58 107
|
||||
f 90 56 45 117
|
||||
f 6 5 99 115
|
||||
f 86 91 107 110
|
||||
f 24 45 56 117
|
||||
f 55 24 56 117
|
||||
f 90 1 89 117
|
||||
f 86 75 91 110
|
||||
f 96 92 7 71
|
||||
f 48 27 99 114
|
||||
f 83 28 99 112
|
||||
f 27 58 47 59
|
||||
f 25 106 107 109
|
||||
f 95 37 85 107
|
||||
f 97 98 80 104
|
||||
f 96 92 71 82
|
||||
f 29 60 28 112
|
||||
f 3 109 110 111
|
||||
f 84 95 85 114
|
||||
f 89 1 113 117
|
||||
f 108 89 113 117
|
||||
f 66 53 32 102
|
||||
f 100 41 29 30
|
||||
f 106 108 113 117
|
||||
f 58 27 47 26
|
||||
f 86 91 85 107
|
||||
f 34 35 23 108
|
||||
f 97 81 100 104
|
||||
f 82 83 96 103
|
||||
f 8 9 97 105
|
||||
f 48 49 99 112
|
||||
f 82 81 100 101
|
||||
f 30 61 50 62
|
||||
f 22 66 11 10
|
||||
f 75 3 91 110
|
||||
f 48 60 49 112
|
||||
f 19 100 101 51
|
||||
f 61 30 50 29
|
||||
f 33 64 53 65
|
||||
f 76 88 77 113
|
||||
f 92 70 81 105
|
||||
f 62 100 50 30
|
||||
f 33 65 53 54
|
||||
f 18 50 51 101
|
||||
f 29 40 81 82
|
||||
f 80 41 81 100
|
||||
f 9 8 100 104
|
||||
f 100 19 101 8
|
||||
f 79 68 10 98
|
||||
f 92 81 101 105
|
||||
f 18 7 50 101
|
||||
f 29 40 41 81
|
||||
f 21 66 22 10
|
||||
f 43 66 78 44
|
||||
f 64 33 53 32
|
||||
f 66 79 43 78
|
||||
f 47 27 48 114
|
||||
f 31 80 42 102
|
||||
f 53 64 32 102
|
||||
f 100 62 50 51
|
||||
f 8 92 101 105
|
||||
f 31 52 100 104
|
||||
f 80 31 100 104
|
||||
f 9 52 102 104
|
||||
f 89 88 108 113
|
||||
f 109 91 110 116
|
||||
f 70 82 92 81
|
||||
f 83 96 103 115
|
||||
f 31 30 42 100
|
||||
f 73 6 94 5
|
||||
f 100 8 101 105
|
||||
f 79 80 98 102
|
||||
f 53 33 66 32
|
||||
f 11 67 79 78
|
||||
f 39 28 83 103
|
||||
f 4 75 3 91
|
||||
f 72 83 94 115
|
||||
f 7 18 50 103
|
||||
f 100 82 101 103
|
||||
f 29 82 100 103
|
||||
f 30 50 29 100
|
||||
f 45 24 56 106
|
||||
f 72 7 96 6
|
||||
f 7 6 103 115
|
||||
f 80 98 102 104
|
||||
f 69 81 97 80
|
||||
f 52 31 102 104
|
||||
f 66 79 10 102
|
||||
f 81 100 101 105
|
||||
f 75 86 93 110
|
||||
f 53 21 20 102
|
||||
f 10 9 21 102
|
||||
f 19 18 51 101
|
||||
f 46 106 109 111
|
||||
f 18 19 7 101
|
||||
f 82 92 81 101
|
||||
f 92 96 7 101
|
||||
f 91 4 114 116
|
||||
f 50 61 29 103
|
||||
f 81 70 97 105
|
||||
f 51 50 100 101
|
||||
f 92 96 101 103
|
||||
f 24 23 108 117
|
||||
f 7 50 101 103
|
||||
f 74 86 75 91
|
||||
f 19 51 52 100
|
||||
f 66 44 32 33
|
||||
f 79 11 66 10
|
||||
f 77 2 76 113
|
||||
f 96 92 82 103
|
||||
f 82 92 101 103
|
||||
f 66 53 21 54
|
||||
f 53 33 54 66
|
||||
f 46 45 106 111
|
||||
f 21 66 54 22
|
||||
f 21 102 66 10
|
||||
f 75 4 74 91
|
||||
f 70 8 97 105
|
||||
f 8 71 7 92
|
||||
f 8 100 104 105
|
||||
f 70 82 71 92
|
||||
f 71 8 70 92
|
||||
f 46 57 58 107
|
||||
f 87 75 86 93
|
||||
f 76 3 75 93
|
||||
f 111 106 113 117
|
||||
f 75 87 76 93
|
||||
f 83 84 72 94
|
||||
f 52 9 20 100
|
||||
f 84 73 72 94
|
||||
f 73 6 72 94
|
||||
f 5 73 84 94
|
||||
f 81 29 82 100
|
||||
f 38 27 26 95
|
||||
f 37 38 26 95
|
||||
f 24 35 106 108
|
||||
f 37 84 38 95
|
||||
f 98 97 9 104
|
||||
f 82 83 71 96
|
||||
f 72 7 71 96
|
||||
f 52 9 100 104
|
||||
f 83 72 71 96
|
||||
f 103 49 61 112
|
||||
f 9 70 8 97
|
||||
f 98 97 69 9
|
||||
f 69 81 70 97
|
||||
f 70 9 69 97
|
||||
f 29 40 82 103
|
||||
f 79 80 68 98
|
||||
f 69 10 68 98
|
||||
f 100 97 104 105
|
||||
f 80 69 68 98
|
||||
f 8 70 92 105
|
||||
f 32 31 43 102
|
||||
f 87 76 93 113
|
||||
f 88 76 87 113
|
||||
f 17 6 49 103
|
||||
f 64 53 52 102
|
||||
f 45 24 106 117
|
||||
f 91 74 85 114
|
||||
f 84 5 94 99
|
||||
f 7 96 6 115
|
||||
f 9 8 104 105
|
||||
f 28 27 99 112
|
||||
f 102 43 66 79
|
||||
f 10 79 98 102
|
||||
f 52 63 31 100
|
||||
f 9 52 20 102
|
||||
f 31 62 30 100
|
||||
f 91 107 110 116
|
||||
f 16 99 116 48
|
||||
f 99 83 112 115
|
||||
f 5 94 99 115
|
||||
f 83 84 94 99
|
||||
f 48 27 112 99
|
||||
f 81 80 100 104
|
||||
f 6 17 49 99
|
||||
f 103 49 112 115
|
||||
f 6 49 103 115
|
||||
f 6 94 5 115
|
||||
f 96 72 6 115
|
||||
f 96 7 103 115
|
||||
f 94 83 99 115
|
||||
f 38 27 95 99
|
||||
f 84 38 95 99
|
||||
f 28 39 83 99
|
||||
f 98 9 102 104
|
||||
f 31 80 102 104
|
||||
f 27 48 112 59
|
||||
f 107 91 114 116
|
||||
f 26 107 114 116
|
||||
f 16 48 49 99
|
||||
f 93 2 111 113
|
||||
f 88 87 108 113
|
||||
f 6 5 17 99
|
||||
f 17 16 49 99
|
||||
f 5 16 17 99
|
||||
f 38 84 83 99
|
||||
f 87 93 106 113
|
||||
f 28 27 39 99
|
||||
f 39 38 83 99
|
||||
f 27 38 39 99
|
||||
f 51 63 52 100
|
||||
f 9 8 20 100
|
||||
f 19 52 20 100
|
||||
f 8 19 20 100
|
||||
f 41 80 42 100
|
||||
f 30 41 42 100
|
||||
f 52 53 20 102
|
||||
f 63 64 52 102
|
||||
f 63 32 64 102
|
||||
f 32 63 31 102
|
||||
f 42 80 79 102
|
||||
f 43 42 79 102
|
||||
f 31 42 43 102
|
||||
f 87 106 108 113
|
||||
f 50 17 49 103
|
||||
f 106 93 110 113
|
||||
f 93 76 2 113
|
||||
f 110 93 111 113
|
||||
f 6 18 7 103
|
||||
f 18 17 50 103
|
||||
f 18 6 17 103
|
||||
f 29 28 40 103
|
||||
f 39 83 82 103
|
||||
f 40 39 82 103
|
||||
f 40 28 39 103
|
||||
f 88 23 89 108
|
||||
f 91 3 109 110
|
||||
f 29 28 103 112
|
||||
f 12 90 45 117
|
||||
f 88 34 23 108
|
||||
f 88 87 34 108
|
||||
f 87 35 34 108
|
||||
f 25 56 24 106
|
||||
f 56 57 45 106
|
||||
f 56 25 57 106
|
||||
f 36 25 24 106
|
||||
f 45 57 46 106
|
||||
f 86 35 87 106
|
||||
f 35 36 24 106
|
||||
f 35 86 36 106
|
||||
f 25 37 26 107
|
||||
f 86 85 36 107
|
||||
f 36 37 25 107
|
||||
f 36 85 37 107
|
||||
f 95 84 99 114
|
||||
f 13 45 111 117
|
||||
f 85 95 107 114
|
||||
f 91 85 107 114
|
||||
f 106 24 108 117
|
||||
f 1 2 113 117
|
||||
f 107 109 110 116
|
||||
f 107 46 109 116
|
||||
f 61 29 103 112
|
||||
f 93 3 110 111
|
||||
f 3 93 2 111
|
||||
f 14 46 109 111
|
||||
f 3 14 109 111
|
||||
f 45 106 111 117
|
||||
f 13 45 46 111
|
||||
f 13 14 2 111
|
||||
f 14 13 46 111
|
||||
f 14 3 2 111
|
||||
f 59 28 60 112
|
||||
f 60 29 61 112
|
||||
f 49 103 61 50
|
||||
f 48 59 60 112
|
||||
f 28 59 27 112
|
||||
f 2 77 1 113
|
||||
f 77 89 1 113
|
||||
f 89 77 88 113
|
||||
f 27 47 26 114
|
||||
f 27 95 99 114
|
||||
f 27 26 95 114
|
||||
f 73 5 84 114
|
||||
f 5 74 4 114
|
||||
f 73 84 85 114
|
||||
f 74 73 85 114
|
||||
f 74 5 73 114
|
||||
f 47 26 114 116
|
||||
f 26 47 107 116
|
||||
f 48 47 114 116
|
||||
f 14 3 109 116
|
||||
f 4 5 114 116
|
||||
f 99 16 116 5
|
||||
f 99 48 114 116
|
||||
f 5 99 114 116
|
||||
f 14 46 47 116
|
||||
f 15 4 3 116
|
||||
f 48 15 47 116
|
||||
f 15 14 47 116
|
||||
f 14 15 3 116
|
||||
f 16 15 48 116
|
||||
f 4 15 16 116
|
||||
f 4 16 5 116
|
||||
f 13 12 45 117
|
||||
f 12 1 90 117
|
||||
f 55 89 23 117
|
||||
f 56 90 55 117
|
||||
f 1 13 2 117
|
||||
f 24 55 23 117
|
||||
f 12 13 1 117
|
1526
cs457-gc/assignment_2_1/data/dinosaur.obj
Normal file
382
cs457-gc/assignment_2_1/notebook/hw_2.1.ipynb
Normal file
@@ -0,0 +1,382 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Description\n",
|
||||
"\n",
|
||||
"This notebook intends to gather all the functionalities you'll have to implement for assignment 2.1. You will have to generate an elastic solid, deform it, compute the associated Jacobian of the deformation map $\\phi$, and implement pinning constraints. You will also visualize the eigenvectors and eigenvalues of the metric tensor, given a prescribed deformation.\n",
|
||||
"\n",
|
||||
"# Load libraries"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import igl\n",
|
||||
"import meshplot as mp\n",
|
||||
"\n",
|
||||
"import sys as _sys\n",
|
||||
"_sys.path.append(\"../src\")\n",
|
||||
"from elasticsolid import *\n",
|
||||
"from eigendecomposition_metric import *\n",
|
||||
"\n",
|
||||
"shadingOptions = {\n",
|
||||
" \"flat\":True,\n",
|
||||
" \"wireframe\":False, \n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"rot = np.array(\n",
|
||||
" [[1, 0, 0 ],\n",
|
||||
" [0, 0, 1],\n",
|
||||
" [0, -1, 0 ]]\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Load mesh\n",
|
||||
"\n",
|
||||
"Several meshes are available for you to play with under `data/`: `ball.obj`, `dinosaur.obj`, and `beam.obj`. You can also uncomment the few commented lines below to manipulate a simple mesh made out of 2 tetrahedra."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "33e8252ccc4d4c9298094b0dc3675ee4",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-1.987469…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"v, _, _, t, _, _ = igl.read_obj(\"../data/dinosaur.obj\")\n",
|
||||
"\n",
|
||||
"# t = np.array([\n",
|
||||
"# [0, 1, 2, 3],\n",
|
||||
"# [1, 2, 3, 4]\n",
|
||||
"# ])\n",
|
||||
"# v = np.array([\n",
|
||||
"# [0., 0., 0.],\n",
|
||||
"# [1., 0., 0.],\n",
|
||||
"# [0., 1., 0.],\n",
|
||||
"# [0., 0., 1.],\n",
|
||||
"# [2/3, 2/3, 2/3]\n",
|
||||
"# ])\n",
|
||||
"\n",
|
||||
"aabb = np.max(v, axis=0) - np.min(v, axis=0)\n",
|
||||
"length_scale = np.mean(aabb)\n",
|
||||
"\n",
|
||||
"p = mp.plot(v @ rot.T, t, shading=shadingOptions)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Manipulate elastic solids\n",
|
||||
"\n",
|
||||
"## Instanciation\n",
|
||||
"\n",
|
||||
"The rest shape matrices $D_m$ and their inverse matrices $B_m$ are computed during instanciation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rho = 131 # [kg.m-3]\n",
|
||||
"solid = ElasticSolid(v, t, rho=rho)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Deform the mesh\n",
|
||||
"\n",
|
||||
"This part involves Jacobian computation which relies on deformed shape matrices $D_s$."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "02c94de8642645d8aab800877f8ddbce",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-1.987469…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<meshplot.Viewer.Viewer at 0x7fa7dc789070>"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"v_def = v.copy()\n",
|
||||
"v_def[:, 2] *= 2.\n",
|
||||
"solid.update_def_shape(v_def)\n",
|
||||
"\n",
|
||||
"mp.plot(solid.v_def @ rot.T, solid.t, shading=shadingOptions)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Visualize some properties of the metric tensor\n",
|
||||
"\n",
|
||||
"The metric tensor measures how stretched and sheared directions in the undeformed space are under the deformation $\\phi$. It is defined from the Jacobian of the deformation $\\mathbf{F}$ as follow (see the handout for a derivation):\n",
|
||||
"\n",
|
||||
"$$\\mathbf{M} = \\mathbf{F}^T \\mathbf{F}$$\n",
|
||||
"\n",
|
||||
"We intend to plot the eigenvectors coloured by the corresponding eigenvalues in the next cell."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "6ff42798692c4a29ad4a37f40ca77a84",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-1.987469…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# We limit ourselves to stretching the mesh in the z direction\n",
|
||||
"# Feel free to experiment with other kinds of deformations!\n",
|
||||
"\n",
|
||||
"v_def = v.copy()\n",
|
||||
"v_def[:, 2] *= 2.0\n",
|
||||
"solid.update_def_shape(v_def)\n",
|
||||
"\n",
|
||||
"squared_eigvals, eigvecs = compute_eigendecomposition_metric(solid.F)\n",
|
||||
"plot_eigendecomposition_metric(solid, squared_eigvals, eigvecs, rot, scale=0.05)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Pin vertices of the mesh\n",
|
||||
"\n",
|
||||
"Pass a `pin_idx` to the constructor, compute the mask for deformations."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"maxZ = np.max(solid.v_rest[:, 2])\n",
|
||||
"pin_idx = np.arange(solid.v_rest.shape[0])[solid.v_rest[:, 2] > maxZ - 0.1 * aabb[2]]\n",
|
||||
"\n",
|
||||
"v_def = v.copy()\n",
|
||||
"v_def[:, 2] -= 0.1 * aabb[2]\n",
|
||||
"solid.update_def_shape(v_def)\n",
|
||||
"\n",
|
||||
"solid_pinned = ElasticSolid(v, t, rho=rho, pin_idx=pin_idx)\n",
|
||||
"solid_pinned.update_def_shape(v_def)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "13f958a33ec945ca979aca15d7381e01",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-1.987469…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"p = mp.plot(solid_pinned.v_def @ rot.T, t, shading=shadingOptions)\n",
|
||||
"p.add_points(solid_pinned.v_def[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.1 * length_scale})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1.2.4 Derivation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Volume of tetrahedron ($X_1, X_2, X_3, X_4$) is given by $\\frac{1}{6}|det(D_m)|$\n",
|
||||
"\n",
|
||||
"We can decompose the provided formula:\n",
|
||||
"\n",
|
||||
"$Vol = \\frac{1}{6}|det(D_m)| = \\frac{1}{6}|D_{m1}^T \\cdot (D_{m2} \\times D_{m3})|$\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Next, we build 3 vectors:\n",
|
||||
"\n",
|
||||
"$V_0 = X_1 - X_4 = \\begin{pmatrix}X_{x1}-X_{x4} \\\\ Y_{x1}-Y_{x4} \\\\ Z_{x1}- Z_{x4} \\end{pmatrix}$\n",
|
||||
"\n",
|
||||
"$V_1 = X_2 - X_4 = \\begin{pmatrix}X_{x2}-X_{x4} \\\\ Y_{x2}-Y_{x4} \\\\ Z_{x2}- Z_{x4} \\end{pmatrix}$\n",
|
||||
"\n",
|
||||
"$V_2 = X_3 - X_4 = \\begin{pmatrix}X_{x3}-X_{x4} \\\\ Y_{x3}-Y_{x4} \\\\ Z_{x3}- Z_{x4} \\end{pmatrix}$\n",
|
||||
"\n",
|
||||
"We then compute the base as:\n",
|
||||
"\n",
|
||||
"$B = V_1 \\times V_2$\n",
|
||||
"\n",
|
||||
"And also the height as:\n",
|
||||
"\n",
|
||||
"$H = V_0$\n",
|
||||
"\n",
|
||||
"From this we can compute the volume:\n",
|
||||
"\n",
|
||||
"$Vol = \\frac{1}{6} \\cdot B \\cdot H = \\frac{1}{6} V_0 \\cdot (V_1 \\times V_2)$\n",
|
||||
"\n",
|
||||
"We can note the similarity between both fomulas. We can note the equality between both formulas: \n",
|
||||
"\n",
|
||||
"$V_0 = D_{m1}, V_1 = D_{m2}, V_2 = D_{m3}$\n",
|
||||
"\n",
|
||||
"Note that the absolute value is not directly taken into account since its absolute volume and not signed volume.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1.2.7 Derivation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Show that: $Vol(x_1, x_2, x_3, x_4)/Vol(X_1, X_2, X_3, X_4) = |det(F)|$\n",
|
||||
"\n",
|
||||
"Since we know that $F = D_s D_m^{-1}$, and that: $V = \\frac{1}{6}|det(D_m)|$\n",
|
||||
"\n",
|
||||
"We can drag the det and abs into it:\n",
|
||||
"\n",
|
||||
"$|det(F)| = \\frac{|det(D_s)|}{|det(D_m)|} = \\frac{\\frac{1}{6}|det(D_s)|}{\\frac{1}{6}|det(D_m)|} = \\frac{Vol(x_1, x_2, x_3, x_4)}{Vol(X_1, X_2, X_3, X_4)}$\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"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"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
@@ -0,0 +1,268 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import time"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Tutorial: Higher Order Array Manipulation\n",
|
||||
"\n",
|
||||
"For the sake of simplicity, we define $n$-th order tensors as arrays of dimension $n$. A $0$-th order array is a scalar, a $1$-st order array is a vector in $\\mathbb{R}^{d_1}$, and a $2$-nd order array is a matrix in $\\mathbb{R}^{d_1\\times d_2}$. Going further, a $n$-th order array is an element of $\\mathbb{R}^{d_1\\times...\\times d_n}$ for some dimensions $(d_i)_{i\\in[n]}$.\n",
|
||||
"\n",
|
||||
"## Declaration"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Declare a third order array \n",
|
||||
"d1, d2, d3 = 2, 3, 5\n",
|
||||
"A = np.random.rand(d1, d2, d3)\n",
|
||||
"\n",
|
||||
"print(\"The shape of A is {}\".format(A.shape))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Indexing\n",
|
||||
"\n",
|
||||
"Say we have a $3$-rd order array $\\mathbf{A}\\in\\mathbb{R}^{d_1\\times d_2\\times d_3}$. Indexing and slicing works as for lower order arrays:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"A[0] has shape {}\".format(A[0].shape))\n",
|
||||
"print(\"A[:, 1:, :] has shape {}\".format(A[:, 1:, :].shape))\n",
|
||||
"print(\"A[:, 1, 2:4] has shape {}\".format(A[:, 1, 2:4].shape))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We can also use a different indexing array $\\mathbf{b}$ to index $\\mathbf{A}$. This indexing operates on the first dimension of $\\mathbf{A}$, meaning that if $\\mathbf{b}\\in\\mathbb{R}^{l_1\\times l_2}$, then `A[b]` will have shape $l_1\\times l_2\\times d_2\\times d_3$."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"b = np.array([0, 0, 1, 0])\n",
|
||||
"print(\"If A has shape {}, b has shape {}, then A[b] has shape {}.\".format(A.shape, b.shape, A[b].shape))\n",
|
||||
"\n",
|
||||
"b = np.array([[0, 0, 1, 0], [1, 1, 0, 1]])\n",
|
||||
"print(\"If A has shape {}, b has shape {}, then A[b] has shape {}.\".format(A.shape, b.shape, A[b].shape))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"... This works provided the indexing array $\\mathbf{b}$ has integer values comprised between $0$ and $d_{1}-1$ (included)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"try:\n",
|
||||
" b = np.array([0, 0, 2, 0])\n",
|
||||
" A[b]\n",
|
||||
"except Exception as e:\n",
|
||||
" print(\"We have an out-of bound indexing: d_1=1 but max b=2\")\n",
|
||||
" print(\"The exception is: {}\".format(e))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Operations\n",
|
||||
"\n",
|
||||
"Imagine now that we have a batch of $1000$ $d\\times d$ matrices: $(\\mathbf{a}_i)_{i\\in[1000]}$, for which we want to compute the trace. We could loop over the matrices and compute the traces separately."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"d = 2\n",
|
||||
"\n",
|
||||
"ais = [np.random.rand(d, d) for i in range(1000)]\n",
|
||||
"\n",
|
||||
"start = time.time()\n",
|
||||
"traces = ...\n",
|
||||
"end = time.time()\n",
|
||||
"\n",
|
||||
"print(\"Elapsed time: {:.2e}s.\".format(end - start))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Alternatively, we could vectorize this operation using a three dimensional array $\\mathbf{A}\\in\\mathbb{R}^{3\\times d\\times d}$ that contains the stacked matrices."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"A = np.stack(ais, axis=0)\n",
|
||||
"\n",
|
||||
"print(\"A has shape {}\".format(A.shape))\n",
|
||||
"\n",
|
||||
"start = time.time()\n",
|
||||
"traces = ...\n",
|
||||
"end = time.time()\n",
|
||||
"\n",
|
||||
"print(\"Elapsed time: {:.2e}s.\".format(end - start))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"And we reduced the computation time by an order of magnitude! A different option that we will use extensively during part 3 is to use [Einstein summation](https://en.wikipedia.org/wiki/Einstein_notation). For the traces computation this would be written: $\\mathbf{A}_{i,j,j}$. This can be done with Numpy with the method [`np.einsum`](https://numpy.org/doc/stable/reference/generated/numpy.einsum.html)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"start = time.time()\n",
|
||||
"traces = ...\n",
|
||||
"end = time.time()\n",
|
||||
"\n",
|
||||
"print(\"Elapsed time: {:.2e}s.\".format(end - start))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"As efficient as the trace method! Also, `np.einsum` is highly flexible. It can compute the transpose of a batch of arrays, or various kinds of matrix multiplications."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"ais = [np.random.rand(2, 3) for i in range(1000)]\n",
|
||||
"\n",
|
||||
"# Transpose each stacked matrices\n",
|
||||
"A = np.stack(ais, axis=0)\n",
|
||||
"print(\"A has shape {}\".format(A.shape))\n",
|
||||
"AT = ...\n",
|
||||
"print(\"A^T has shape {}\".format(AT.shape))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Below we show how to compute $\\mathbf{a}_i^T\\mathbf{a}_i$ for some matrices $\\mathbf{a}_i\\in\\mathbb{R}^{2\\times 3}$ using `np.einsum`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"A has shape {}\".format(A.shape))\n",
|
||||
"product_As = ...\n",
|
||||
"print(\"Stacked ai^T.ai has shape {}\".format(product_As.shape))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"To scale each $\\mathbf{a}_i$ by a weight $w_i$, we can still use `np.einsum`. Define the vector containing all the weights $\\mathbf{w}=(w_i)_i$, we have:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"w = np.random.rand(A.shape[0])\n",
|
||||
"weighted_A = ...\n",
|
||||
"print(\"Weighted and stacked ai has shape {}\".format(weighted_A.shape))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"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.7.10"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
96
cs457-gc/assignment_2_1/src/eigendecomposition_metric.py
Normal file
@@ -0,0 +1,96 @@
|
||||
import numpy as np
|
||||
import meshplot as mp
|
||||
import igl
|
||||
|
||||
def compute_eigendecomposition_metric(jac):
|
||||
'''
|
||||
Input:
|
||||
- jac : a np array of shape (#t, 3, 3) containing the stacked jacobians
|
||||
|
||||
Output:
|
||||
- squared_eigvals : np array of shape (#t, 3) containing the square root of the eigenvalues of the metric tensor
|
||||
- eigvecs : np array of shape (#t, 3, 3) containing the eigenvectors of the metric tensor
|
||||
'''
|
||||
|
||||
jact = np.transpose(jac,(0,2,1))
|
||||
smt = jact @ jac
|
||||
|
||||
eigvals, eigvecs = np.linalg.eigh(smt)
|
||||
return np.sqrt(eigvals), eigvecs #/ np.linalg.norm(eigvecs)
|
||||
|
||||
def plot_eigendecomposition_metric(solid, squared_eigvals, eigvecs, rot, scale=0.05):
|
||||
'''
|
||||
Input:
|
||||
- solid : an ElasticSolid object
|
||||
- squared_eigvals : np array of shape (#t, 3) containing the square root of the eigenvalues of the metric tensor
|
||||
- eigvecs : np array of shape (#t, 3, 3) containing the eigenvectors of the metric tensor
|
||||
- rot : a rotation matrix for plotting purposes
|
||||
- scale : scaling for plotting purposes
|
||||
'''
|
||||
|
||||
scaled_eigvecs = scale * np.einsum('ik, ijk -> ijk', squared_eigvals, eigvecs)
|
||||
|
||||
start_plot0 = (solid.def_barycenters - scaled_eigvecs[..., 0]) @ rot.T
|
||||
start_plot1 = (solid.def_barycenters - scaled_eigvecs[..., 1]) @ rot.T
|
||||
start_plot2 = (solid.def_barycenters - scaled_eigvecs[..., 2]) @ rot.T
|
||||
end_plot0 = (solid.def_barycenters + scaled_eigvecs[..., 0]) @ rot.T
|
||||
end_plot1 = (solid.def_barycenters + scaled_eigvecs[..., 1]) @ rot.T
|
||||
end_plot2 = (solid.def_barycenters + scaled_eigvecs[..., 2]) @ rot.T
|
||||
|
||||
# Get boundary edges
|
||||
be = igl.edges(igl.boundary_facets(solid.t))
|
||||
|
||||
p = mp.plot(solid.v_def @ rot.T, be, shading={"line_color": "black"})
|
||||
p.add_points(solid.def_barycenters @ rot.T, shading={"point_color":"black", "point_size": 0.2})
|
||||
|
||||
# In tension
|
||||
tens0 = np.argwhere(squared_eigvals[:, 0]>1. + 1e-6)
|
||||
tens1 = np.argwhere(squared_eigvals[:, 1]>1. + 1e-6)
|
||||
tens2 = np.argwhere(squared_eigvals[:, 2]>1. + 1e-6)
|
||||
if tens0.shape[0] != 0:
|
||||
p.add_lines(start_plot0[tens0, :],
|
||||
end_plot0[tens0, :],
|
||||
shading={"line_color": "#182C94"})
|
||||
if tens1.shape[0] != 0:
|
||||
p.add_lines(start_plot1[tens1, :],
|
||||
end_plot1[tens1, :],
|
||||
shading={"line_color": "#182C94"})
|
||||
if tens2.shape[0] != 0:
|
||||
p.add_lines(start_plot2[tens2, :],
|
||||
end_plot2[tens2, :],
|
||||
shading={"line_color": "#182C94"})
|
||||
|
||||
# In compression
|
||||
comp0 = np.argwhere(squared_eigvals[:, 0]<1. - 1e-6)
|
||||
comp1 = np.argwhere(squared_eigvals[:, 1]<1. - 1e-6)
|
||||
comp2 = np.argwhere(squared_eigvals[:, 2]<1. - 1e-6)
|
||||
if comp0.shape[0] != 0:
|
||||
p.add_lines(start_plot0[comp0, :],
|
||||
end_plot0[comp0, :],
|
||||
shading={"line_color": "#892623"})
|
||||
if comp1.shape[0] != 0:
|
||||
p.add_lines(start_plot1[comp1, :],
|
||||
end_plot1[comp1, :],
|
||||
shading={"line_color": "#892623"})
|
||||
if comp2.shape[0] != 0:
|
||||
p.add_lines(start_plot2[comp2, :],
|
||||
end_plot2[comp2, :],
|
||||
shading={"line_color": "#892623"})
|
||||
|
||||
# Neutral
|
||||
# In compression
|
||||
neut0 = np.argwhere(abs(squared_eigvals[:, 0]-1.) < 1e-6)
|
||||
neut1 = np.argwhere(abs(squared_eigvals[:, 1]-1.) < 1e-6)
|
||||
neut2 = np.argwhere(abs(squared_eigvals[:, 2]-1.) < 1e-6)
|
||||
if neut0.shape[0] != 0:
|
||||
p.add_lines(start_plot0[neut0, :],
|
||||
end_plot0[neut0, :],
|
||||
shading={"line_color": "#027337"})
|
||||
if neut1.shape[0] != 0:
|
||||
p.add_lines(start_plot1[neut1, :],
|
||||
end_plot1[neut1, :],
|
||||
shading={"line_color": "#027337"})
|
||||
if neut2.shape[0] != 0:
|
||||
p.add_lines(start_plot2[neut2, :],
|
||||
end_plot2[neut2, :],
|
||||
shading={"line_color": "#027337"})
|
175
cs457-gc/assignment_2_1/src/elasticsolid.py
Normal file
@@ -0,0 +1,175 @@
|
||||
import numpy as np
|
||||
from numpy import linalg
|
||||
from scipy import sparse
|
||||
import igl
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
# ELASTIC SOLID CLASS
|
||||
# -----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
class ElasticSolid(object):
|
||||
|
||||
def __init__(self, v_rest, t, rho=1, pin_idx=[]):
|
||||
'''
|
||||
Input:
|
||||
- v_rest : position of the vertices of the mesh (#v, 3)
|
||||
- t : indices of the element's vertices (#t, 4)
|
||||
- rho : mass per unit volume [kg.m-3]
|
||||
- pin_idx : list of vertex indices to pin
|
||||
'''
|
||||
|
||||
self.v_rest = v_rest.copy()
|
||||
self.v_def = v_rest.copy()
|
||||
self.t = t
|
||||
self.rho = rho
|
||||
self.pin_idx = pin_idx
|
||||
self.free_idx = None
|
||||
self.pin_mask = None
|
||||
|
||||
self.W0 = None
|
||||
self.Dm = None
|
||||
self.Bm = None
|
||||
self.rest_barycenters = None
|
||||
|
||||
self.W = None
|
||||
self.Ds = None
|
||||
self.F = None
|
||||
self.def_barycenters = None
|
||||
|
||||
self.make_free_indices_and_pin_mask()
|
||||
self.update_rest_shape(self.v_rest)
|
||||
self.update_def_shape(self.v_def)
|
||||
|
||||
## Precomputation ##
|
||||
|
||||
def make_free_indices_and_pin_mask(self):
|
||||
'''
|
||||
Should list all the free indices and the pin mask.
|
||||
|
||||
Updated attributes:
|
||||
- free_index : np array of shape (#free_vertices,) containing the list of unpinned vertices
|
||||
- pin_mask : np array of shape (#v, 1) containing 1 at free vertex indices and 0 at pinned vertex indices
|
||||
'''
|
||||
self.pin_mask = np.ones((self.v_rest.shape[0],1))
|
||||
self.pin_mask[self.pin_idx] = 0
|
||||
self.free_idx = np.where(self.pin_mask==1)[0]
|
||||
|
||||
## Methods related to rest quantities ##
|
||||
|
||||
def make_rest_barycenters(self):
|
||||
'''
|
||||
Construct the barycenters of the undeformed configuration
|
||||
|
||||
Updated attributes:
|
||||
- rest_barycenters : np array of shape (#t, 3) containing the position of each tet's barycenter
|
||||
'''
|
||||
self.rest_barycenters = np.einsum("ijk->ik",self.v_rest[self.t[:,:]])/4
|
||||
|
||||
def make_rest_shape_matrices(self):
|
||||
'''
|
||||
Construct Dm that has shape (#t, 3, 3), and its inverse Bm
|
||||
|
||||
Updated attributes:
|
||||
- Dm : np array of shape (#t, 3, 3) containing the shape matrix of each tet
|
||||
- Bm : np array of shape (#t, 3, 3) containing the inverse shape matrix of each tet
|
||||
'''
|
||||
tv = self.v_rest[self.t[:,:]]
|
||||
|
||||
tva = tv[:,:3,:]
|
||||
tvb = tv[:,3,:].reshape((self.t.shape[0],1,3))
|
||||
tvb= np.repeat(tvb, 3, axis=1)
|
||||
|
||||
tvs = tva - tvb
|
||||
tvsf = np.transpose(tvs,(0,2,1))
|
||||
|
||||
self.Dm = tvsf
|
||||
self.Bm = np.linalg.inv(tvsf)
|
||||
|
||||
def update_rest_shape(self, v_rest):
|
||||
'''
|
||||
Updates the vertex position, the shape matrices Dm and Bm, the volumes W0,
|
||||
and the mass matrix at rest
|
||||
|
||||
Input:
|
||||
- v_rest : position of the vertices of the mesh at rest state (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- v_rest : np array of shape (#v, 3) containing the position of each vertex at rest
|
||||
- W0 : np array of shape (#t) containing the volume of each tet
|
||||
'''
|
||||
self.v_rest = v_rest
|
||||
self.make_rest_barycenters()
|
||||
self.make_rest_shape_matrices()
|
||||
self.W0 = -np.linalg.det(self.Dm)/6
|
||||
|
||||
self.update_def_shape(self.v_def)
|
||||
|
||||
## Methods related to deformed quantities ##
|
||||
|
||||
def make_def_barycenters(self):
|
||||
'''
|
||||
Construct the barycenters of the deformed configuration
|
||||
|
||||
Updated attributes:
|
||||
- def_barycenters : np array of shape (#t, 3) containing the position of each tet's barycenter
|
||||
'''
|
||||
self.def_barycenters = np.einsum("ijk->ik",self.v_def[self.t[:,:]])/4
|
||||
|
||||
def make_def_shape_matrices(self):
|
||||
'''
|
||||
Construct Ds that has shape (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- Ds : np array of shape (#t, 3, 3) containing the shape matrix of each tet
|
||||
'''
|
||||
tv = self.v_def[self.t[:,:]]
|
||||
|
||||
tva = tv[:,:3,:]
|
||||
tvb = tv[:,3,:].reshape((self.t.shape[0],1,3))
|
||||
tvb= np.repeat(tvb, 3, axis=1)
|
||||
|
||||
tvs = tva - tvb
|
||||
tvsf = np.transpose(tvs,(0,2,1))
|
||||
|
||||
self.Ds = tvsf
|
||||
|
||||
def make_jacobians(self):
|
||||
'''
|
||||
Compute the current Jacobian of the deformation
|
||||
|
||||
Updated attributes:
|
||||
- F : np array of shape (#t, 3, 3) containing Jacobian of the deformation in each tet
|
||||
'''
|
||||
self.F = self.Ds @ self.Bm
|
||||
|
||||
def update_def_shape(self, v_def):
|
||||
'''
|
||||
Updates the vertex position, the Jacobian of the deformation, and the
|
||||
resulting elastic forces.
|
||||
|
||||
Input:
|
||||
- v_def : position of the vertices of the mesh (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- v_def : np array of shape (#v, 3) containing the position of each vertex after deforming the solid
|
||||
- W : np array of shape (#t, 3) containing the volume of each tet
|
||||
'''
|
||||
self.v_def = self.v_rest
|
||||
self.v_def[self.free_idx] = v_def[self.free_idx]
|
||||
self.make_def_barycenters()
|
||||
self.make_def_shape_matrices()
|
||||
self.W = -np.linalg.det(self.Ds)/6
|
||||
self.make_jacobians()
|
||||
|
||||
def displace(self, v_disp):
|
||||
'''
|
||||
Displace the whole mesh so that v_def += v_disp
|
||||
|
||||
Input:
|
||||
- v_disp : displacement of the vertices of the mesh (#v, 3)
|
||||
'''
|
||||
self.update_def_shape(self.v_def + v_disp)
|
116
cs457-gc/assignment_2_1/test/test.py
Normal file
@@ -0,0 +1,116 @@
|
||||
import time
|
||||
import pytest
|
||||
import json
|
||||
import sys
|
||||
import igl
|
||||
import numpy as np
|
||||
sys.path.append('../')
|
||||
sys.path.append('../src')
|
||||
from elasticsolid import *
|
||||
from eigendecomposition_metric import *
|
||||
eps = 1E-6
|
||||
|
||||
with open('test_data1.json', 'r') as infile:
|
||||
homework_datas = json.load(infile)
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[0])
|
||||
def test_rest_barycenters(data):
|
||||
v, t, rest_barycenters_gt = data
|
||||
es = ElasticSolid(np.array(v), np.array(t))
|
||||
es.make_rest_barycenters()
|
||||
rest_barycenters_student = es.rest_barycenters
|
||||
if(len(v) > 5000):
|
||||
return
|
||||
assert np.linalg.norm(rest_barycenters_gt - rest_barycenters_student) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[1])
|
||||
def test_rest_shape_matrices(data):
|
||||
v, t, Dm_gt, Bm_gt = data
|
||||
es = ElasticSolid(np.array(v), np.array(t))
|
||||
es.make_rest_shape_matrices()
|
||||
Dm, Bm = es.Dm, es.Bm
|
||||
if(len(v) > 5000):
|
||||
return
|
||||
assert np.linalg.norm(Dm - Dm_gt) < eps
|
||||
assert np.linalg.norm(Bm - Bm_gt) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[2])
|
||||
def test_def_barycenters(data):
|
||||
v, t, v_def, def_barycenters_gt = data
|
||||
es = ElasticSolid(np.array(v), np.array(t))
|
||||
es.v_def = np.array(v_def)
|
||||
es.make_def_barycenters()
|
||||
def_barycenters_student = es.def_barycenters
|
||||
if(len(v) > 5000):
|
||||
return
|
||||
assert np.linalg.norm(def_barycenters_gt - def_barycenters_student ) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[3])
|
||||
def test_def_shape_matrices(data):
|
||||
v, t, v_def, Ds_gt = data
|
||||
es = ElasticSolid(np.array(v), np.array(t))
|
||||
es.v_def = np.array(v_def)
|
||||
es.make_def_shape_matrices()
|
||||
Ds = es.Ds
|
||||
if(len(v) > 5000):
|
||||
return
|
||||
assert np.linalg.norm(Ds - Ds_gt) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[4])
|
||||
def test_update_rest_shape(data):
|
||||
v, t, v_update, rest_barycenters_gt, W0_gt, F_gt = data
|
||||
es = ElasticSolid(np.array(v), np.array(t))
|
||||
es.update_rest_shape(np.array(v_update))
|
||||
if(len(v) > 5000):
|
||||
return
|
||||
assert np.linalg.norm(es.rest_barycenters - rest_barycenters_gt) < eps
|
||||
assert np.linalg.norm(es.W0 - W0_gt) < eps
|
||||
assert np.linalg.norm(es.F - F_gt) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[5])
|
||||
def test_update_def_shape(data):
|
||||
v, t, v_def, def_barycenters_gt, W_gt, F_gt = data
|
||||
es = ElasticSolid(np.array(v), np.array(t))
|
||||
es.update_def_shape(np.array(v_def))
|
||||
if(len(v) > 5000):
|
||||
return
|
||||
assert np.linalg.norm(es.def_barycenters - def_barycenters_gt) < eps
|
||||
assert np.linalg.norm(es.W - W_gt) < eps
|
||||
assert np.linalg.norm(es.F - F_gt) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[6])
|
||||
def test_jacobians(data):
|
||||
v, t, v_def, Ds_gt, Bm_gt, F_gt = data
|
||||
es = ElasticSolid(np.array(v), np.array(t))
|
||||
es.v_def, es.Ds, es.Bm = np.array(v_def), np.array(Ds_gt), np.array(Bm_gt)
|
||||
es.make_jacobians()
|
||||
if(len(v) > 5000):
|
||||
return
|
||||
assert np.linalg.norm(es.F - F_gt) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[7])
|
||||
def test_pinning(data):
|
||||
v, t, pin_idx, free_idx_gt, pin_mask_gt = data
|
||||
es = ElasticSolid(np.array(v), np.array(t), pin_idx = np.array(pin_idx))
|
||||
if(len(v) > 5000):
|
||||
return
|
||||
assert np.linalg.norm(es.free_idx - free_idx_gt) < eps
|
||||
assert np.linalg.norm(es.pin_mask.astype(float) - np.array(pin_mask_gt).astype(float)) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[8])
|
||||
def test_eig(data):
|
||||
F, eigvals_gt, eigvecs_gt = data
|
||||
eigvals, eigvecs = compute_eigendecomposition_metric(np.array(F))
|
||||
if(len(F) > 5000):
|
||||
return
|
||||
assert np.linalg.norm(eigvals - eigvals_gt) < eps
|
||||
assert np.linalg.norm(abs(np.diagonal(np.einsum('ijk, ijl -> ikl', eigvecs, eigvecs_gt), axis1 = 1, axis2 = 2)) - 1) < eps
|
1
cs457-gc/assignment_2_1/test/test_data1.json
Normal file
834
cs457-gc/assignment_2_2/data/ball.obj
Normal file
@@ -0,0 +1,834 @@
|
||||
v 3.06161699786838e-17 -7.49879891330929e-33 0.5
|
||||
v 3.06161699786838e-17 -7.49879891330929e-33 -0.5
|
||||
v 0.154508497187474 -3.78436673043416e-17 -0.475528258147577
|
||||
v 0.293892626146237 -7.19829327805997e-17 -0.404508497187474
|
||||
v 0.404508497187474 -9.90760072617093e-17 -0.293892626146236
|
||||
v 0.475528258147577 -1.16470831848909e-16 -0.154508497187473
|
||||
v 0.5 -1.22464679914735e-16 7.6571373978539e-16
|
||||
v 0.475528258147577 -1.16470831848909e-16 0.154508497187474
|
||||
v 0.404508497187474 -9.90760072617092e-17 0.293892626146237
|
||||
v 0.293892626146237 -7.19829327805998e-17 0.404508497187473
|
||||
v 0.154508497187475 -3.78436673043417e-17 0.475528258147576
|
||||
v 0.21857645514496 0.136716465258129 0.428407447861946
|
||||
v 0.475945187701446 -0.132880263668928 0.0762824608354488
|
||||
v 0.218576349120797 -0.134908613951094 -0.428980239040003
|
||||
v 0.228603425820446 -0.140038091834834 0.422054269660211
|
||||
v 0.437104447096958 0.151793486569612 0.189468835862535
|
||||
v 0.42898023903994 0.134908613950884 -0.21857634912105
|
||||
v 0.428980239039898 -0.134908613951062 -0.218576349121023
|
||||
v 0.218576349121032 0.134908613951053 -0.428980239039896
|
||||
v 0.340440645253916 0.134908613951044 0.34044064525392
|
||||
v 0.476615030125843 -0.131924241455095 -0.0737163996315581
|
||||
v 0.407622547196207 -0.259520994885 -0.128423955051913
|
||||
v 0.338436818269637 -0.252043139096244 -0.26820659215246
|
||||
v 0.340989631871085 -0.116746524471516 -0.34654915954341
|
||||
v 0.075316277025205 -0.134908613951047 0.475528258147578
|
||||
v 0.0753162770252058 0.134908613951052 -0.475528258147577
|
||||
v 0.337051887252752 0.13152434625125 -0.345104870499591
|
||||
v 0.342307229899869 0.259749321291958 -0.255648294433281
|
||||
v 0.235302886190634 0.257758938760451 0.358040334654413
|
||||
v 0.0930553185121102 0.241091096498632 0.428037137273972
|
||||
v 0.414887348894352 0.253233345682864 -0.117223548665273
|
||||
v 0.309219636002729 0.365205559163796 -0.144941768535501
|
||||
v 0.116382730487621 0.357335962703667 0.329797013029059
|
||||
v 0.220295554503833 0.356044147287606 -0.273317459830304
|
||||
v 0.173924737961772 0.443407381211481 -0.152118637293744
|
||||
v 0.0757439138278267 0.415836842579461 -0.2671003179923
|
||||
v 0.0224933467184133 0.480041055177656 -0.138038526134294
|
||||
v 0.248065266401332 0.358015947011543 0.245536566096914
|
||||
v 0.138163331821839 0.43047956133561 0.21353744639334
|
||||
v 0.360552014587397 0.346405942121308 -0.00227333235984791
|
||||
v 0.123093945281709 0.484207258358844 -0.0197790694319915
|
||||
v -0.0375624502146155 0.498585389330104 0.0012930121510933
|
||||
v -0.0319756224028659 0.329253812136088 0.374925975048146
|
||||
v -0.0571707300985015 0.188277472409031 0.459655415505214
|
||||
v 0.44634465869394 0.222444950782125 0.0359817943817138
|
||||
v 0.114071738612042 0.30750614917439 -0.377395822274126
|
||||
v 0.236387555749274 0.430565411758525 0.0934577427723124
|
||||
v 0.378115930351658 0.292151103254715 0.147227973161872
|
||||
v 0.0698331513994325 -0.131524346251195 -0.477309833660296
|
||||
v -0.0276507157238025 0.368077837732622 -0.337274581446689
|
||||
v -0.132019323454869 0.46789161623721 -0.116826083086996
|
||||
v -0.178527337205295 0.268217150323689 0.382344805303572
|
||||
v -0.195982573985885 0.117715178528912 0.444672876885665
|
||||
v -0.188769871137012 0.462097824846099 0.0288363663352296
|
||||
v -0.311118332326446 0.185953595932789 0.344422187801651
|
||||
v 0.298513275017753 -0.364576673892107 -0.167253321318123
|
||||
v -0.27446477920923 0.408828269442573 -0.0867671082739308
|
||||
v -0.321076581736832 0.0337877006396921 0.381796044958135
|
||||
v -0.406068994209582 0.0890512487956863 0.27780901178606
|
||||
v -0.396337226815336 -0.0658166787739775 0.297632268807486
|
||||
v 0.137344602759695 -0.267387515925555 0.399550217644719
|
||||
v -0.469353412437567 -0.00745235730436951 0.172197086513736
|
||||
v -0.438850244007533 -0.16046355744979 0.17793793880195
|
||||
v -0.488260481987745 -0.0978280168539874 0.0450708425427184
|
||||
v -0.433483128474169 -0.244453321072111 0.0483213321946162
|
||||
v -0.460620100758965 -0.173287974513347 -0.0883198769579221
|
||||
v -0.383511806626786 -0.309356779000242 -0.08495338406711
|
||||
v -0.336717499334961 -0.365993326701377 0.0516740791080927
|
||||
v -0.267862281691792 -0.414575366652434 -0.0798565176542698
|
||||
v -0.205085219904653 -0.452251021719178 0.0583872069088724
|
||||
v -0.389473197418456 -0.226083984285031 -0.217247924138414
|
||||
v -0.445256364809781 -0.0799966822341631 -0.212949055945092
|
||||
v -0.00351125947165275 -0.267035886479874 0.422704987418922
|
||||
v -0.353169743739217 -0.125114465368412 -0.331085340452809
|
||||
v -0.38892388844103 0.0261181792321889 -0.313139026174485
|
||||
v -0.278756909608118 -0.262391732725563 -0.321628922740179
|
||||
v -0.249429844449192 -0.39750217428021 0.172559480007787
|
||||
v -0.125203314206269 -0.478452051724907 -0.0735375027587528
|
||||
v -0.0528582364531956 -0.493487744300911 0.0606288138087549
|
||||
v 0.271731582933658 -0.249600298700644 0.337433901267964
|
||||
v -0.495847117939593 0.0542719818547096 0.034499095880349
|
||||
v 0.341636271151409 -0.364235836672196 -0.0248377438078891
|
||||
v -0.278221380393658 -0.0165162196036634 -0.415114535979952
|
||||
v -0.385894465893779 0.231366911979078 0.218070661102819
|
||||
v 0.129422773211733 -0.26368230955868 -0.404624993543385
|
||||
v 0.17079787798835 -0.360453290963367 0.301498772648173
|
||||
v -0.2972397651044 0.134475553784439 -0.378899521608367
|
||||
v -0.390729424978202 0.17308135749756 -0.259563788196669
|
||||
v 0.0302401087170613 -0.494617483324727 -0.0666264287973931
|
||||
v -0.0447104151313644 -0.455911463185833 -0.200363960118914
|
||||
v -0.289781305004565 -0.107480642258869 0.393032704503674
|
||||
v -0.28072748874216 0.276043192337753 -0.308208100199367
|
||||
v 0.106085899784673 -0.483055958177403 0.0735032185430484
|
||||
v -0.143288452953271 0.380504725979635 0.291006138693707
|
||||
v -0.0207720062787277 -0.262149359393134 -0.425260199319106
|
||||
v -0.0793282266177742 -0.112493174960849 0.480679017691543
|
||||
v -0.210229488803243 0.104747954203238 -0.441397131988602
|
||||
v 0.435024352571936 -0.127806035969131 0.210759174982314
|
||||
v 0.298839864283654 -0.34288662805342 0.207661974894498
|
||||
v -0.343961566185834 -0.213169748618088 0.293681969588004
|
||||
v -0.217656630917657 -0.259665634918282 0.367694641054313
|
||||
v -0.318981501523703 0.381763369474201 0.0500752574969736
|
||||
v -0.395445063483211 0.303503289973959 -0.0388452666581461
|
||||
v 0.00695685172784659 -0.466794760772503 0.179037017204205
|
||||
v -0.141786434074944 -0.0639250457860653 -0.475194902785753
|
||||
v 0.123376202006679 -0.445805073774975 -0.189831896621448
|
||||
v 0.0273264572598231 -0.36207385125428 -0.343737968475292
|
||||
v -0.179178868825853 0.231344360320625 -0.40543152308883
|
||||
v -0.131442519100517 -0.37228536331636 -0.30680037880178
|
||||
v 0.213344976802497 -0.44944368426887 -0.0498427080320272
|
||||
v -0.095411435088729 0.468568967697982 0.146081417588813
|
||||
v 0.19556911033449 -0.349389679263868 -0.299465482329545
|
||||
v -0.212579734450761 0.392914303643436 -0.22456225527287
|
||||
v 0.00442729082563762 0.431790532829453 0.252066131907487
|
||||
v 0.251435921428911 -0.424020659066107 0.0835850351458869
|
||||
v -0.0716881267417996 0.0362403081699758 0.493505271043782
|
||||
v 0.409702957808806 -0.250532734704164 0.139200701163351
|
||||
v 0.354048851093961 -0.123591021755264 0.33071841554491
|
||||
v -0.409329654955812 0.269763307055223 0.0983717019288848
|
||||
v -0.23775056881332 0.409432492346691 0.160747321096556
|
||||
v -0.280167779637764 0.310303261210272 0.274258821799984
|
||||
v 0.0390199999029228 -0.340176969429353 0.364358434892671
|
||||
v -0.106955495739533 -0.389774683020182 0.294340310538035
|
||||
v -0.125152025350624 -0.457070129870627 0.159448634144933
|
||||
v 0.250205349609497 0.430527105380925 -0.0452072401182732
|
||||
v -0.15862733630032 -0.0449406159687499 0.472035707563119
|
||||
v -0.372118237460504 -0.283526014116421 0.176468174662014
|
||||
v -0.235245742246689 -0.152187819676347 -0.41412354231191
|
||||
v 0.479986141812706 0.124680814448665 -0.063780860578784
|
||||
v -0.0761042573074939 0.431963531953512 -0.240032600039915
|
||||
v -0.288453021308633 -0.353652776154199 -0.204265925734934
|
||||
v -0.458840137015611 0.057463941494015 -0.190167358112447
|
||||
v -0.444083105517519 0.194920415588484 -0.121639742603844
|
||||
v -0.178055249060845 -0.43316536366806 -0.175111667230364
|
||||
v -0.491963173165518 -0.0298523928793253 -0.0841490991531884
|
||||
v -0.45636138284715 0.138396610027018 0.150268648023688
|
||||
v -0.345904715972311 0.313415014736247 -0.179223201639723
|
||||
v -0.153169726530236 -0.269052072762942 -0.392619430258638
|
||||
v -0.0419923946510265 0.170189522618945 -0.468265058681734
|
||||
v 0.243612070418092 0.241981955824921 -0.363452737232445
|
||||
v 0.338867576345089 0.252678472264692 0.2670624559087
|
||||
v 0.426863022631355 -0.25994025908482 0.0147993789376581
|
||||
v 0.158342102182598 -0.434609327079221 0.18984865417522
|
||||
v 0.0452931243905481 0.0952764475019849 0.488744239285072
|
||||
v -0.237259629761916 0.0166159415076913 0.439808797744033
|
||||
v 0.247175666187241 -0.238473344419651 -0.363365730423495
|
||||
v 0.0577997827759178 0.48434516267528 0.10985876616872
|
||||
v -0.334770924239934 0.332574086299653 0.165296416795679
|
||||
v -0.153183582101622 0.339412359720881 -0.333667559470828
|
||||
v 0.36785960116632 -0.228792320684729 0.249666553277471
|
||||
v 0.483390586525237 0.102332156736947 0.0765615475049495
|
||||
v 0.139648641361451 0.213951152339616 -0.429794324507027
|
||||
v -0.0358864034291634 0.302032201639968 -0.396848478920397
|
||||
v -0.180786711862885 -0.175443810495746 0.431897712627121
|
||||
v 0.348215026659532 -0.346723777603642 0.0923521372398145
|
||||
v -0.114480413553308 -0.290654614949134 0.390402522688358
|
||||
v -0.272442803422386 -0.321472772094441 0.269128548588341
|
||||
v -0.466114498296331 0.180818120755528 0.00648703972541844
|
||||
v -0.129415184584831 -0.203585571998795 -0.437955048918034
|
||||
v 0.0643376427947934 -0.412575814735467 0.275030661590622
|
||||
v -0.485934856252322 0.0906364933467189 -0.0751820560562512
|
||||
v -2.77555756156289e-16 3.19189119579733e-16 -1.2490009027033e-16
|
||||
v -0.251828742757562 0.0139490906784806 -0.0181338406388946
|
||||
v 0.197996662720562 -0.0791211777945037 0.136432807235424
|
||||
v 0.125255777218953 0.210831018463626 -0.063969097850248
|
||||
v -0.139628236563409 -0.21265335644906 0.00545121255949739
|
||||
v -0.145223690886062 0.189924594351579 0.11159305462841
|
||||
v -0.112897563504534 -0.0373976158431084 -0.223966661594476
|
||||
v 0.225528258147577 -0.0232431701377701 -0.114912387106339
|
||||
v -0.118530098445147 -0.0689806932344922 0.2117841676383
|
||||
v 0.098269738040353 0.147959392484917 0.178021817259433
|
||||
v 0.100852235573853 -0.219450649709681 -0.0387973024559412
|
||||
v -0.100480207820675 0.192284757140571 -0.148991345058649
|
||||
v 0.08807336311451 0.0516996280513727 -0.271061939721184
|
||||
v 0.272113071694785 0.101244013250397 0.0512575837900759
|
||||
v 0.0341720627218518 -0.221571915156144 0.170600381517002
|
||||
v 0.113793744063312 -0.150466918879953 -0.232830800332848
|
||||
v 0.068592399702004 -0.0245878691620408 0.288679790541826
|
||||
v -0.0741210186337665 0.111594614690448 0.278407708187608
|
||||
v -0.0351094203418499 0.30351870487887 -0.00261521319733849
|
||||
v -0.258447343925187 0.0495111872633636 0.167086499211952
|
||||
v -0.271439309774019 -0.125349807194904 0.104052998028547
|
||||
v -0.0485204373172835 -0.250891695571267 -0.169649174254392
|
||||
v -0.245408905954284 -0.137064807392418 -0.132337064396614
|
||||
v -0.247561324014027 0.19563057757812 -0.0400712992459122
|
||||
v -0.245489451032576 0.0855397985783712 -0.187709278356085
|
||||
v 0.27254656245515 -0.16399276001755 -0.00766125806031415
|
||||
v 0.273716986928946 0.149504817170547 -0.136480234333616
|
||||
v 0.0525334922800396 0.245214764318482 -0.222591039627852
|
||||
v -0.025453222260026 0.265072731295802 0.212780231418037
|
||||
v 0.10188342337719 0.303246953287615 0.102540160700209
|
||||
v -0.14157478784597 -0.241776139413833 0.180194715613577
|
||||
v -0.0121617817639016 -0.325829668630181 0.0394634260162139
|
||||
v 0.222619980200421 0.0438990087026778 0.254181668630204
|
||||
v 0.187862004819913 -0.26556009247797 0.101876795667186
|
||||
v 0.342239361396159 -0.0424148965243595 0.0738730045314498
|
||||
v -0.120466338945889 0.114580505991094 -0.297963959751455
|
||||
v 0.15154406307463 -0.163641254596307 0.268108582070898
|
||||
f 166 170 163 182
|
||||
f 165 162 171 180
|
||||
f 167 171 162 180
|
||||
f 4 5 27 169
|
||||
f 163 166 162 170
|
||||
f 4 24 169 177
|
||||
f 167 173 163 185
|
||||
f 162 163 167 173
|
||||
f 158 136 181 185
|
||||
f 162 171 170 178
|
||||
f 162 163 170 181
|
||||
f 162 167 163 181
|
||||
f 4 169 27 174
|
||||
f 170 171 162 179
|
||||
f 162 173 165 174
|
||||
f 170 178 171 179
|
||||
f 158 181 163 185
|
||||
f 162 176 164 178
|
||||
f 162 170 167 181
|
||||
f 162 170 176 178
|
||||
f 162 166 163 184
|
||||
f 167 170 162 179
|
||||
f 129 169 6 196
|
||||
f 162 165 169 174
|
||||
f 73 176 170 178
|
||||
f 119 181 136 185
|
||||
f 4 169 174 177
|
||||
f 72 132 135 163
|
||||
f 27 174 169 188
|
||||
f 158 119 136 185
|
||||
f 64 66 163 182
|
||||
f 167 162 171 179
|
||||
f 66 135 64 163
|
||||
f 7 129 6 196
|
||||
f 162 173 167 180
|
||||
f 95 177 168 183
|
||||
f 162 177 172 183
|
||||
f 4 24 5 169
|
||||
f 27 169 5 188
|
||||
f 162 169 165 175
|
||||
f 162 164 169 175
|
||||
f 129 175 169 196
|
||||
f 168 177 162 183
|
||||
f 132 161 135 163
|
||||
f 119 148 84 167
|
||||
f 162 165 173 180
|
||||
f 164 162 171 175
|
||||
f 165 171 162 175
|
||||
f 158 81 161 163
|
||||
f 30 171 178 179
|
||||
f 64 81 62 163
|
||||
f 169 162 174 177
|
||||
f 66 163 182 184
|
||||
f 169 177 23 187
|
||||
f 162 170 166 176
|
||||
f 54 167 102 185
|
||||
f 68 166 67 182
|
||||
f 162 168 163 173
|
||||
f 164 171 162 178
|
||||
f 161 158 163 185
|
||||
f 65 68 67 182
|
||||
f 166 168 162 183
|
||||
f 129 6 169 188
|
||||
f 162 163 168 184
|
||||
f 165 175 40 191
|
||||
f 129 169 175 188
|
||||
f 119 167 84 181
|
||||
f 62 64 163 182
|
||||
f 18 169 23 187
|
||||
f 67 182 166 184
|
||||
f 162 168 166 184
|
||||
f 168 174 162 177
|
||||
f 164 162 169 172
|
||||
f 167 181 119 185
|
||||
f 126 178 170 179
|
||||
f 72 163 135 184
|
||||
f 72 132 163 186
|
||||
f 54 180 167 185
|
||||
f 62 163 81 181
|
||||
f 162 168 173 174
|
||||
f 66 135 163 184
|
||||
f 165 174 173 189
|
||||
f 38 141 171 191
|
||||
f 140 174 188 189
|
||||
f 161 163 132 186
|
||||
f 24 23 18 169
|
||||
f 62 163 181 182
|
||||
f 65 182 67 184
|
||||
f 166 162 172 183
|
||||
f 140 174 27 188
|
||||
f 162 166 172 176
|
||||
f 4 14 24 177
|
||||
f 23 169 24 177
|
||||
f 169 172 162 177
|
||||
f 163 173 168 186
|
||||
f 60 181 170 182
|
||||
f 119 148 167 185
|
||||
f 57 173 51 180
|
||||
f 72 163 184 186
|
||||
f 41 35 165 180
|
||||
f 41 37 35 180
|
||||
f 141 171 48 175
|
||||
f 56 177 172 187
|
||||
f 135 161 81 163
|
||||
f 95 49 168 177
|
||||
f 102 54 120 167
|
||||
f 34 140 188 189
|
||||
f 176 178 73 198
|
||||
f 162 172 164 176
|
||||
f 141 171 175 194
|
||||
f 60 170 91 182
|
||||
f 130 37 180 189
|
||||
f 56 23 177 187
|
||||
f 22 18 23 187
|
||||
f 121 55 167 179
|
||||
f 6 169 21 196
|
||||
f 60 91 100 182
|
||||
f 12 30 171 178
|
||||
f 65 66 182 184
|
||||
f 91 170 100 182
|
||||
f 164 172 169 187
|
||||
f 116 178 126 179
|
||||
f 125 165 40 191
|
||||
f 69 67 166 184
|
||||
f 96 73 170 178
|
||||
f 113 51 57 173
|
||||
f 57 173 180 185
|
||||
f 136 119 84 181
|
||||
f 84 167 121 181
|
||||
f 83 75 74 186
|
||||
f 134 131 69 183
|
||||
f 167 179 55 181
|
||||
f 130 180 173 189
|
||||
f 145 179 170 181
|
||||
f 48 171 141 191
|
||||
f 48 175 171 191
|
||||
f 102 167 148 185
|
||||
f 64 135 81 163
|
||||
f 30 178 144 179
|
||||
f 57 180 54 185
|
||||
f 121 52 55 179
|
||||
f 40 175 165 188
|
||||
f 60 91 170 181
|
||||
f 130 51 173 180
|
||||
f 76 183 168 184
|
||||
f 74 75 72 184
|
||||
f 140 19 27 174
|
||||
f 165 180 171 191
|
||||
f 49 174 168 177
|
||||
f 83 74 168 186
|
||||
f 84 121 55 181
|
||||
f 69 70 78 166
|
||||
f 120 167 54 180
|
||||
f 121 167 55 181
|
||||
f 148 121 84 167
|
||||
f 74 128 168 184
|
||||
f 131 166 69 183
|
||||
f 156 170 176 192
|
||||
f 74 75 184 186
|
||||
f 67 68 69 166
|
||||
f 65 67 66 184
|
||||
f 117 164 150 196
|
||||
f 96 156 154 170
|
||||
f 98 150 164 196
|
||||
f 145 170 58 181
|
||||
f 161 133 158 185
|
||||
f 24 18 5 169
|
||||
f 78 183 166 193
|
||||
f 34 32 165 188
|
||||
f 98 117 150 196
|
||||
f 41 35 125 165
|
||||
f 35 34 32 165
|
||||
f 73 156 170 176
|
||||
f 74 184 168 186
|
||||
f 72 184 75 186
|
||||
f 133 161 132 186
|
||||
f 119 102 148 185
|
||||
f 150 164 117 195
|
||||
f 34 188 165 189
|
||||
f 57 54 102 185
|
||||
f 148 102 120 167
|
||||
f 170 181 163 182
|
||||
f 12 178 171 194
|
||||
f 6 18 21 169
|
||||
f 5 169 6 188
|
||||
f 136 62 81 181
|
||||
f 171 180 167 190
|
||||
f 58 170 91 181
|
||||
f 78 166 70 193
|
||||
f 2 168 49 174
|
||||
f 34 140 28 188
|
||||
f 40 125 32 165
|
||||
f 38 48 141 191
|
||||
f 169 174 165 188
|
||||
f 40 175 48 191
|
||||
f 113 130 51 173
|
||||
f 66 72 135 184
|
||||
f 169 187 21 196
|
||||
f 131 166 183 184
|
||||
f 74 128 83 168
|
||||
f 18 21 169 187
|
||||
f 7 6 21 196
|
||||
f 64 65 66 182
|
||||
f 69 166 131 184
|
||||
f 56 112 172 177
|
||||
f 76 168 128 184
|
||||
f 166 182 68 192
|
||||
f 159 95 168 183
|
||||
f 34 165 35 189
|
||||
f 96 170 126 178
|
||||
f 172 183 89 193
|
||||
f 150 118 98 164
|
||||
f 172 177 106 183
|
||||
f 168 183 166 184
|
||||
f 111 167 120 180
|
||||
f 17 5 6 188
|
||||
f 30 171 179 190
|
||||
f 130 37 51 180
|
||||
f 40 165 32 188
|
||||
f 100 182 170 192
|
||||
f 112 106 172 177
|
||||
f 74 76 128 184
|
||||
f 170 179 167 181
|
||||
f 32 125 35 165
|
||||
f 41 165 125 191
|
||||
f 113 173 57 185
|
||||
f 2 168 174 197
|
||||
f 18 6 5 169
|
||||
f 167 180 111 190
|
||||
f 126 170 145 179
|
||||
f 12 144 30 178
|
||||
f 91 126 154 170
|
||||
f 69 68 70 166
|
||||
f 4 27 19 174
|
||||
f 137 92 173 186
|
||||
f 25 73 178 198
|
||||
f 29 171 141 194
|
||||
f 60 58 91 181
|
||||
f 120 167 111 190
|
||||
f 111 120 54 180
|
||||
f 150 118 164 198
|
||||
f 30 33 29 171
|
||||
f 69 131 67 184
|
||||
f 95 49 159 168
|
||||
f 68 182 127 192
|
||||
f 117 187 164 196
|
||||
f 166 176 170 192
|
||||
f 33 171 30 190
|
||||
f 57 51 54 180
|
||||
f 137 92 113 173
|
||||
f 22 23 56 187
|
||||
f 37 36 35 189
|
||||
f 29 38 141 171
|
||||
f 150 164 195 198
|
||||
f 180 190 171 191
|
||||
f 145 91 58 170
|
||||
f 41 180 165 191
|
||||
f 82 187 172 195
|
||||
f 137 173 185 186
|
||||
f 113 137 173 185
|
||||
f 112 106 177 183
|
||||
f 164 187 117 195
|
||||
f 154 170 156 192
|
||||
f 148 120 121 167
|
||||
f 165 188 174 189
|
||||
f 76 138 168 183
|
||||
f 116 96 126 178
|
||||
f 76 138 128 168
|
||||
f 82 56 172 187
|
||||
f 172 176 166 193
|
||||
f 9 98 118 164
|
||||
f 30 29 12 171
|
||||
f 70 166 192 193
|
||||
f 33 38 29 171
|
||||
f 165 175 169 188
|
||||
f 96 73 156 170
|
||||
f 141 175 16 194
|
||||
f 96 25 73 178
|
||||
f 45 175 40 188
|
||||
f 98 164 9 196
|
||||
f 121 94 52 190
|
||||
f 106 56 112 172
|
||||
f 70 68 77 166
|
||||
f 70 192 124 193
|
||||
f 169 175 164 196
|
||||
f 31 45 40 188
|
||||
f 172 177 169 187
|
||||
f 106 89 172 183
|
||||
f 113 149 130 173
|
||||
f 149 189 173 197
|
||||
f 121 167 94 190
|
||||
f 171 175 165 191
|
||||
f 93 110 193 195
|
||||
f 172 193 110 195
|
||||
f 125 40 47 191
|
||||
f 3 49 14 177
|
||||
f 96 154 126 170
|
||||
f 78 90 183 193
|
||||
f 152 26 174 189
|
||||
f 113 57 137 185
|
||||
f 16 194 175 196
|
||||
f 60 62 181 182
|
||||
f 110 82 172 195
|
||||
f 92 149 113 173
|
||||
f 146 23 24 177
|
||||
f 34 28 32 188
|
||||
f 163 185 173 186
|
||||
f 72 75 132 186
|
||||
f 91 145 126 170
|
||||
f 38 171 33 191
|
||||
f 124 192 104 193
|
||||
f 18 22 21 187
|
||||
f 77 166 68 192
|
||||
f 130 36 37 189
|
||||
f 30 179 43 190
|
||||
f 131 183 76 184
|
||||
f 89 110 172 193
|
||||
f 121 120 94 167
|
||||
f 9 164 118 194
|
||||
f 173 174 168 197
|
||||
f 12 171 29 194
|
||||
f 56 23 112 177
|
||||
f 116 1 96 178
|
||||
f 17 27 5 188
|
||||
f 140 27 28 188
|
||||
f 104 192 176 193
|
||||
f 120 94 167 190
|
||||
f 112 177 107 183
|
||||
f 82 56 110 172
|
||||
f 169 164 187 196
|
||||
f 164 175 171 194
|
||||
f 118 194 164 198
|
||||
f 3 174 49 177
|
||||
f 9 164 194 196
|
||||
f 70 166 77 192
|
||||
f 167 180 173 185
|
||||
f 146 24 14 177
|
||||
f 30 44 43 179
|
||||
f 101 154 156 192
|
||||
f 152 174 140 189
|
||||
f 166 182 163 184
|
||||
f 92 149 173 197
|
||||
f 171 190 33 191
|
||||
f 60 63 62 182
|
||||
f 45 129 175 188
|
||||
f 163 181 167 185
|
||||
f 150 195 99 198
|
||||
f 167 179 171 190
|
||||
f 143 193 176 195
|
||||
f 164 176 172 195
|
||||
f 171 178 164 194
|
||||
f 164 178 176 198
|
||||
f 9 194 16 196
|
||||
f 129 17 6 188
|
||||
f 78 89 90 193
|
||||
f 10 118 15 194
|
||||
f 10 15 178 194
|
||||
f 150 99 80 198
|
||||
f 83 186 168 197
|
||||
f 111 190 180 191
|
||||
f 77 68 127 192
|
||||
f 127 68 65 182
|
||||
f 118 15 194 198
|
||||
f 10 15 11 178
|
||||
f 19 3 4 174
|
||||
f 9 16 8 196
|
||||
f 45 31 129 188
|
||||
f 30 144 44 179
|
||||
f 149 153 189 197
|
||||
f 40 32 31 188
|
||||
f 159 168 138 183
|
||||
f 124 123 104 192
|
||||
f 89 183 90 193
|
||||
f 104 176 143 193
|
||||
f 62 63 64 182
|
||||
f 137 185 133 186
|
||||
f 178 194 15 198
|
||||
f 47 40 48 191
|
||||
f 89 110 106 172
|
||||
f 75 83 87 186
|
||||
f 123 176 104 192
|
||||
f 105 49 2 168
|
||||
f 107 177 95 183
|
||||
f 87 186 83 197
|
||||
f 173 186 92 197
|
||||
f 73 122 176 198
|
||||
f 159 138 95 183
|
||||
f 149 153 50 189
|
||||
f 112 107 106 183
|
||||
f 137 133 88 186
|
||||
f 120 111 94 190
|
||||
f 110 56 106 172
|
||||
f 93 193 143 195
|
||||
f 170 182 166 192
|
||||
f 173 180 165 189
|
||||
f 10 178 11 194
|
||||
f 114 190 111 191
|
||||
f 52 53 55 179
|
||||
f 173 189 174 197
|
||||
f 139 174 26 189
|
||||
f 19 140 152 174
|
||||
f 116 145 53 179
|
||||
f 36 34 35 189
|
||||
f 100 127 182 192
|
||||
f 116 126 145 179
|
||||
f 134 78 90 183
|
||||
f 112 23 146 177
|
||||
f 89 93 110 193
|
||||
f 115 110 93 195
|
||||
f 63 60 100 182
|
||||
f 159 128 138 168
|
||||
f 11 144 12 178
|
||||
f 46 140 34 189
|
||||
f 168 184 163 186
|
||||
f 16 175 151 196
|
||||
f 106 90 89 183
|
||||
f 76 131 109 183
|
||||
f 41 42 37 180
|
||||
f 2 3 26 174
|
||||
f 143 176 86 195
|
||||
f 70 77 124 192
|
||||
f 137 88 92 186
|
||||
f 16 151 8 196
|
||||
f 73 122 156 176
|
||||
f 3 2 49 174
|
||||
f 150 80 118 198
|
||||
f 155 117 187 195
|
||||
f 160 143 104 176
|
||||
f 84 55 59 181
|
||||
f 25 61 73 198
|
||||
f 33 30 43 190
|
||||
f 166 183 172 193
|
||||
f 105 168 2 197
|
||||
f 107 85 95 177
|
||||
f 150 117 99 195
|
||||
f 79 78 70 193
|
||||
f 141 16 20 194
|
||||
f 16 141 48 175
|
||||
f 111 180 147 191
|
||||
f 45 129 151 175
|
||||
f 86 195 176 198
|
||||
f 156 122 123 176
|
||||
f 122 86 176 198
|
||||
f 11 178 12 194
|
||||
f 29 141 20 194
|
||||
f 92 108 149 197
|
||||
f 156 176 123 192
|
||||
f 82 22 56 187
|
||||
f 160 104 123 176
|
||||
f 95 85 49 177
|
||||
f 48 40 45 175
|
||||
f 84 59 136 181
|
||||
f 51 37 42 180
|
||||
f 105 159 49 168
|
||||
f 13 187 117 196
|
||||
f 43 179 52 190
|
||||
f 139 174 189 197
|
||||
f 134 109 131 183
|
||||
f 160 86 143 176
|
||||
f 96 1 25 178
|
||||
f 114 111 147 191
|
||||
f 59 55 58 181
|
||||
f 19 26 3 174
|
||||
f 99 195 86 198
|
||||
f 110 115 82 195
|
||||
f 155 187 82 195
|
||||
f 60 62 59 181
|
||||
f 71 74 72 184
|
||||
f 25 178 15 198
|
||||
f 158 103 119 185
|
||||
f 152 140 46 189
|
||||
f 175 194 164 196
|
||||
f 43 44 52 179
|
||||
f 164 172 187 195
|
||||
f 59 62 136 181
|
||||
f 100 157 127 192
|
||||
f 93 104 143 193
|
||||
f 15 25 11 178
|
||||
f 59 58 60 181
|
||||
f 73 61 122 198
|
||||
f 99 86 80 198
|
||||
f 54 51 42 180
|
||||
f 102 119 103 185
|
||||
f 67 71 66 184
|
||||
f 71 72 66 184
|
||||
f 39 33 190 191
|
||||
f 64 63 65 182
|
||||
f 152 139 26 189
|
||||
f 160 123 122 176
|
||||
f 39 38 33 191
|
||||
f 132 88 133 186
|
||||
f 21 187 13 196
|
||||
f 92 186 87 197
|
||||
f 124 79 70 193
|
||||
f 2 26 139 174
|
||||
f 76 109 138 183
|
||||
f 114 39 33 190
|
||||
f 38 47 48 191
|
||||
f 117 13 142 187
|
||||
f 142 155 117 187
|
||||
f 153 152 46 189
|
||||
f 25 1 11 178
|
||||
f 41 147 42 180
|
||||
f 42 111 54 180
|
||||
f 98 13 117 196
|
||||
f 122 61 86 198
|
||||
f 105 83 128 168
|
||||
f 176 192 166 193
|
||||
f 107 112 85 177
|
||||
f 122 86 160 176
|
||||
f 41 147 180 191
|
||||
f 76 74 71 184
|
||||
f 13 21 142 187
|
||||
f 2 174 139 197
|
||||
f 131 71 67 184
|
||||
f 85 146 14 177
|
||||
f 142 82 155 187
|
||||
f 36 130 50 189
|
||||
f 97 87 83 197
|
||||
f 87 92 88 186
|
||||
f 41 125 47 191
|
||||
f 42 147 111 180
|
||||
f 83 168 105 197
|
||||
f 155 99 117 195
|
||||
f 155 82 115 195
|
||||
f 45 151 16 175
|
||||
f 57 102 103 185
|
||||
f 49 85 14 177
|
||||
f 158 133 103 185
|
||||
f 39 190 114 191
|
||||
f 44 144 116 179
|
||||
f 115 93 143 195
|
||||
f 8 98 9 196
|
||||
f 1 144 11 178
|
||||
f 63 100 127 182
|
||||
f 168 186 173 197
|
||||
f 146 85 112 177
|
||||
f 139 189 153 197
|
||||
f 108 153 149 197
|
||||
f 52 44 53 179
|
||||
f 32 28 31 188
|
||||
f 44 116 53 179
|
||||
f 108 92 87 197
|
||||
f 21 22 142 187
|
||||
f 176 195 164 198
|
||||
f 90 106 107 183
|
||||
f 10 11 12 194
|
||||
f 138 107 95 183
|
||||
f 82 142 22 187
|
||||
f 28 27 17 188
|
||||
f 7 21 13 196
|
||||
f 131 76 71 184
|
||||
f 100 101 157 192
|
||||
f 176 193 172 195
|
||||
f 20 16 9 194
|
||||
f 152 26 19 174
|
||||
f 88 132 75 186
|
||||
f 164 194 178 198
|
||||
f 129 31 17 188
|
||||
f 57 103 137 185
|
||||
f 127 65 63 182
|
||||
f 159 105 128 168
|
||||
f 139 152 153 189
|
||||
f 138 109 107 183
|
||||
f 137 103 133 185
|
||||
f 79 89 78 193
|
||||
f 94 43 52 190
|
||||
f 16 48 45 175
|
||||
f 25 15 61 198
|
||||
f 36 46 34 189
|
||||
f 12 29 20 194
|
||||
f 75 87 88 186
|
||||
f 77 127 157 192
|
||||
f 9 118 10 194
|
||||
f 111 114 94 190
|
||||
f 97 83 105 197
|
||||
f 99 143 86 195
|
||||
f 80 15 118 198
|
||||
f 8 151 7 196
|
||||
f 124 104 79 193
|
||||
f 134 90 109 183
|
||||
f 39 114 147 191
|
||||
f 33 43 114 190
|
||||
f 79 93 89 193
|
||||
f 77 123 124 192
|
||||
f 36 50 46 189
|
||||
f 79 104 93 193
|
||||
f 31 28 17 188
|
||||
f 97 105 139 197
|
||||
f 61 80 86 198
|
||||
f 139 105 2 197
|
||||
f 109 90 107 183
|
||||
f 8 7 13 196
|
||||
f 143 99 115 195
|
||||
f 98 8 13 196
|
||||
f 47 38 39 191
|
||||
f 41 47 147 191
|
||||
f 153 46 50 189
|
||||
f 157 101 123 192
|
||||
f 94 114 43 190
|
||||
f 115 99 155 195
|
||||
f 157 123 77 192
|
||||
f 12 20 10 194
|
||||
f 156 123 101 192
|
||||
f 61 15 80 198
|
||||
f 20 9 10 194
|
||||
f 47 39 147 191
|
||||
f 97 108 87 197
|
||||
f 139 153 108 197
|
||||
f 139 108 97 197
|
||||
f 181 158 81 136
|
||||
f 181 81 158 163
|
||||
f 69 183 78 134
|
||||
f 78 183 69 166
|
||||
f 185 161 186 163
|
||||
f 185 186 161 133
|
||||
f 180 35 189 37
|
||||
f 180 189 35 165
|
||||
f 179 121 190 167
|
||||
f 179 190 121 52
|
||||
f 177 3 4 14
|
||||
f 177 4 3 174
|
||||
f 55 181 53 58
|
||||
f 55 53 181 179
|
||||
f 145 53 181 58
|
||||
f 145 181 53 179
|
||||
f 100 192 91 101
|
||||
f 100 91 192 170
|
||||
f 154 91 192 101
|
||||
f 154 192 91 170
|
||||
f 196 129 151 7
|
||||
f 196 151 129 175
|
||||
f 189 149 130 50
|
||||
f 189 130 149 173
|
||||
f 116 178 144 1
|
||||
f 116 144 178 179
|
278
cs457-gc/assignment_2_2/data/beam.obj
Normal file
@@ -0,0 +1,278 @@
|
||||
v 0 1 0
|
||||
v 1 1 0
|
||||
v 2 1 0
|
||||
v 3 1 0
|
||||
v 4 1 0
|
||||
v 5 1 0
|
||||
v 6 1 0
|
||||
v 7 1 0
|
||||
v 8 1 0
|
||||
v 9 1 0
|
||||
v 10 1 0
|
||||
v 0 0 0
|
||||
v 1 0 0
|
||||
v 2 0 0
|
||||
v 3 0 0
|
||||
v 4 0 0
|
||||
v 5 0 0
|
||||
v 6 0 0
|
||||
v 7 0 0
|
||||
v 8 0 0
|
||||
v 9 0 0
|
||||
v 10 0 0
|
||||
v 0 1 2
|
||||
v 1 1 2
|
||||
v 2 1 2
|
||||
v 3 1 2
|
||||
v 4 1 2
|
||||
v 5 1 2
|
||||
v 6 1 2
|
||||
v 7 1 2
|
||||
v 8 1 2
|
||||
v 9 1 2
|
||||
v 10 1 2
|
||||
v 0 2 2
|
||||
v 1 2 2
|
||||
v 2 2 2
|
||||
v 3 2 2
|
||||
v 4 2 2
|
||||
v 5 2 2
|
||||
v 6 2 2
|
||||
v 7 2 2
|
||||
v 8 2 2
|
||||
v 9 2 2
|
||||
v 10 2 2
|
||||
v 1 0 1
|
||||
v 2 0 1
|
||||
v 3 0 1
|
||||
v 4 0 1
|
||||
v 5 0 1
|
||||
v 6 0 1
|
||||
v 7 0 1
|
||||
v 8 0 1
|
||||
v 9 0 1
|
||||
v 10 0 1
|
||||
v 0 0 2
|
||||
v 1 0 2
|
||||
v 2 0 2
|
||||
v 3 0 2
|
||||
v 4 0 2
|
||||
v 5 0 2
|
||||
v 6 0 2
|
||||
v 7 0 2
|
||||
v 8 0 2
|
||||
v 9 0 2
|
||||
v 10 0 2
|
||||
v 10 1 1
|
||||
v 10 2 0
|
||||
v 9 2 0
|
||||
v 8 2 0
|
||||
v 7 2 0
|
||||
v 6 2 0
|
||||
v 5 2 0
|
||||
v 4 2 0
|
||||
v 3 2 0
|
||||
v 2 2 0
|
||||
v 1 2 0
|
||||
v 0 2 0
|
||||
v 10 2 1
|
||||
v 9 2 1
|
||||
v 8 2 1
|
||||
v 7 2 1
|
||||
v 6 2 1
|
||||
v 5 2 1
|
||||
v 4 2 1
|
||||
v 3 2 1
|
||||
v 2 2 1
|
||||
v 1 2 1
|
||||
v 0 2 1
|
||||
v 0 1 1
|
||||
v 0 0 1
|
||||
f 36 86 25 24
|
||||
f 1 87 88 89
|
||||
f 12 13 1 45
|
||||
f 85 38 37 26
|
||||
f 87 35 23 24
|
||||
f 48 85 4 47
|
||||
f 61 28 49 60
|
||||
f 46 14 2 3
|
||||
f 9 31 8 52
|
||||
f 85 37 25 26
|
||||
f 19 7 18 51
|
||||
f 61 28 50 49
|
||||
f 49 28 27 60
|
||||
f 85 5 4 73
|
||||
f 3 85 4 74
|
||||
f 28 61 50 29
|
||||
f 32 31 43 79
|
||||
f 23 45 90 89
|
||||
f 28 39 40 82
|
||||
f 10 54 53 21
|
||||
f 48 85 47 26
|
||||
f 48 85 5 4
|
||||
f 7 50 18 51
|
||||
f 50 28 29 6
|
||||
f 85 4 74 73
|
||||
f 88 87 23 89
|
||||
f 77 1 76 87
|
||||
f 13 46 14 2
|
||||
f 1 12 45 90
|
||||
f 87 35 34 23
|
||||
f 1 2 87 89
|
||||
f 9 53 20 21
|
||||
f 29 28 82 6
|
||||
f 29 82 7 6
|
||||
f 48 49 16 5
|
||||
f 25 47 58 46
|
||||
f 15 48 16 4
|
||||
f 16 48 5 4
|
||||
f 2 1 45 89
|
||||
f 1 2 76 87
|
||||
f 8 30 7 51
|
||||
f 35 86 36 24
|
||||
f 45 1 90 89
|
||||
f 76 2 86 87
|
||||
f 80 30 41 81
|
||||
f 85 5 73 84
|
||||
f 30 62 29 51
|
||||
f 50 29 7 6
|
||||
f 23 24 45 89
|
||||
f 77 1 87 88
|
||||
f 76 2 75 86
|
||||
f 48 85 26 27
|
||||
f 2 86 87 24
|
||||
f 3 74 75 86
|
||||
f 3 85 74 86
|
||||
f 3 24 86 2
|
||||
f 2 3 75 86
|
||||
f 23 87 24 89
|
||||
f 30 80 41 42
|
||||
f 28 5 27 83
|
||||
f 30 29 41 81
|
||||
f 47 58 59 26
|
||||
f 15 48 4 47
|
||||
f 88 87 34 23
|
||||
f 87 86 35 24
|
||||
f 13 2 1 45
|
||||
f 55 23 45 90
|
||||
f 86 85 36 25
|
||||
f 13 46 2 45
|
||||
f 46 25 24 57
|
||||
f 5 73 84 72
|
||||
f 36 85 37 25
|
||||
f 3 85 86 25
|
||||
f 25 3 24 86
|
||||
f 85 84 38 27
|
||||
f 10 11 66 54
|
||||
f 59 48 26 27
|
||||
f 48 47 59 26
|
||||
f 46 25 57 58
|
||||
f 23 56 55 45
|
||||
f 85 48 5 27
|
||||
f 85 38 26 27
|
||||
f 23 24 56 45
|
||||
f 46 24 2 45
|
||||
f 3 25 24 46
|
||||
f 3 24 2 46
|
||||
f 24 46 57 45
|
||||
f 24 57 56 45
|
||||
f 87 2 24 89
|
||||
f 24 2 45 89
|
||||
f 47 25 3 46
|
||||
f 3 15 4 47
|
||||
f 10 11 54 22
|
||||
f 14 15 3 47
|
||||
f 46 14 3 47
|
||||
f 49 28 5 27
|
||||
f 48 49 5 27
|
||||
f 47 25 58 26
|
||||
f 85 5 84 27
|
||||
f 47 85 3 26
|
||||
f 9 80 31 79
|
||||
f 47 25 26 3
|
||||
f 3 85 25 26
|
||||
f 85 47 3 4
|
||||
f 48 49 27 60
|
||||
f 59 48 27 60
|
||||
f 31 9 53 52
|
||||
f 50 61 62 29
|
||||
f 33 32 78 66
|
||||
f 31 80 30 42
|
||||
f 40 29 82 81
|
||||
f 63 62 30 51
|
||||
f 30 63 51 52
|
||||
f 41 29 40 81
|
||||
f 33 32 66 54
|
||||
f 9 80 68 69
|
||||
f 82 71 70 7
|
||||
f 5 84 83 72
|
||||
f 32 43 78 79
|
||||
f 29 28 40 82
|
||||
f 5 84 27 83
|
||||
f 33 32 44 78
|
||||
f 9 80 79 68
|
||||
f 8 7 19 51
|
||||
f 28 27 39 83
|
||||
f 28 39 82 83
|
||||
f 28 50 49 6
|
||||
f 65 64 32 53
|
||||
f 82 71 7 6
|
||||
f 29 82 81 7
|
||||
f 81 70 8 7
|
||||
f 84 38 27 83
|
||||
f 27 38 39 83
|
||||
f 32 43 44 78
|
||||
f 9 31 32 79
|
||||
f 31 80 42 79
|
||||
f 31 42 43 79
|
||||
f 67 78 10 11
|
||||
f 32 9 10 53
|
||||
f 62 50 29 51
|
||||
f 71 82 83 6
|
||||
f 49 16 5 17
|
||||
f 81 82 70 7
|
||||
f 50 49 6 17
|
||||
f 79 68 67 10
|
||||
f 79 9 68 10
|
||||
f 50 6 18 17
|
||||
f 78 10 11 66
|
||||
f 78 79 67 10
|
||||
f 32 9 79 10
|
||||
f 78 32 79 66
|
||||
f 79 32 10 66
|
||||
f 78 79 10 66
|
||||
f 9 10 53 21
|
||||
f 82 28 83 6
|
||||
f 71 83 72 6
|
||||
f 69 81 70 8
|
||||
f 64 31 53 52
|
||||
f 28 5 83 6
|
||||
f 83 5 72 6
|
||||
f 80 30 81 8
|
||||
f 28 49 5 6
|
||||
f 64 63 31 52
|
||||
f 80 81 69 8
|
||||
f 9 80 69 8
|
||||
f 7 50 6 18
|
||||
f 80 9 31 8
|
||||
f 80 31 30 8
|
||||
f 31 63 30 52
|
||||
f 31 30 8 52
|
||||
f 30 81 8 7
|
||||
f 30 29 81 7
|
||||
f 19 8 51 52
|
||||
f 33 65 32 54
|
||||
f 49 5 6 17
|
||||
f 10 54 21 22
|
||||
f 29 50 7 51
|
||||
f 30 29 7 51
|
||||
f 65 32 54 53
|
||||
f 9 53 52 20
|
||||
f 31 9 32 53
|
||||
f 64 31 32 53
|
||||
f 32 10 66 53
|
||||
f 66 10 54 53
|
||||
f 32 66 54 53
|
||||
f 8 30 51 52
|
||||
f 8 9 52 20
|
||||
f 19 8 52 20
|
1526
cs457-gc/assignment_2_2/data/dinosaur.obj
Normal file
BIN
cs457-gc/assignment_2_2/hw_2.2.pdf
Normal file
454
cs457-gc/assignment_2_2/notebook/hw_2.2.ipynb
Normal file
223
cs457-gc/assignment_2_2/notebook/test_fd.ipynb
Normal file
431
cs457-gc/assignment_2_2/src/Utils.py
Normal file
@@ -0,0 +1,431 @@
|
||||
import numpy as np
|
||||
import time
|
||||
import math
|
||||
|
||||
def conjugate_gradient(L_method, b):
|
||||
'''
|
||||
Finds an inexact Newton descent direction using Conjugate Gradient (CG)
|
||||
Solves partially L(x) = b where A is positive definite, using CG.
|
||||
The method should be take care of checking whether the added direction is
|
||||
an ascent direction or not, and whether the residuals are small enough.
|
||||
Details can be found in the handout.
|
||||
|
||||
Input:
|
||||
- L_method : a method that computes the Hessian vector product. It should
|
||||
take an array of shape (n,) and return an array of shape (n,)
|
||||
- b : right hand side of the linear system (n,)
|
||||
|
||||
Output:
|
||||
- p_star : np array of shape (n,) solving the linear system approximately
|
||||
'''
|
||||
N = b.shape[0]
|
||||
fshape = (3*N,N)
|
||||
z = np.zeros(fshape)
|
||||
r = np.zeros(fshape)
|
||||
d = np.zeros(fshape)
|
||||
alpha = np.zeros(3*N)
|
||||
beta = np.zeros(3*N)
|
||||
r[0] = -b
|
||||
d[0] = -r[0]
|
||||
ck = 0
|
||||
for k in range(0,3*N):
|
||||
|
||||
if (d[k].T @ L_method(d[k]) <= 0).all():
|
||||
if (k==0):
|
||||
return b
|
||||
else:
|
||||
return z[k]
|
||||
alpha[k] = (r[k].T @ r[k])/(d[k].T @ L_method(d[k]))
|
||||
z[k+1] = z[k] + alpha[k]*d[k]
|
||||
r[k+1] = r[k] + alpha[k]*L_method(d[k])
|
||||
if (np.linalg.norm(r[k+1]) < min(0.5,math.sqrt(np.linalg.norm(b)))*math.sqrt(np.linalg.norm(b) )):
|
||||
break
|
||||
|
||||
beta[k+1] = (r[k].T @ r[k+1])/(r[k].T @ r[k])
|
||||
d[k+1] = -r[k+1] + beta[k+1]*d[k]
|
||||
ck = k
|
||||
|
||||
return z[ck+1]
|
||||
|
||||
|
||||
def compute_inverse_approximate_hessian_matrix(sk, yk, invB_prev):
|
||||
'''
|
||||
Input:
|
||||
- sk : previous step x_{k+1} - x_k, shape (n, 1)
|
||||
- yk : grad(f)_{k+1} - grad(f)_{k}, shape (n, 1)
|
||||
- invB_prev : previous Hessian estimate Bk, shape (n, n)
|
||||
|
||||
Output:
|
||||
- invB_new : previous Hessian estimate Bk, shape (n, n)
|
||||
'''
|
||||
invB_new = invB_prev.copy()
|
||||
invB_new += (sk.T @ yk + yk.T @ invB_prev @ yk) / ((sk.T @ yk) ** 2) * (sk @ sk.T)
|
||||
prod = (invB_prev @ yk) @ sk.T
|
||||
invB_new -= (prod + prod.T) / (sk.T @ yk)
|
||||
return invB_new
|
||||
|
||||
def evaluate_armijo_rule(f_x, f_x1, p, grad, c, alpha):
|
||||
"""
|
||||
Check the armijo rule, return true if the armijo condition is satisfied
|
||||
|
||||
Input:
|
||||
- f_x : float
|
||||
The function value at x
|
||||
- f_x1 : float
|
||||
The function value at x_(k+1) = x_k + alpha * p_k
|
||||
- p: np.array(2 * #V, 1)
|
||||
The flatten search direction
|
||||
Here, we use the flatten the search direction.
|
||||
The flatten process asks the all x coordinates to be first
|
||||
then all y cooridnates to be the second.
|
||||
- grad: np.array(2 * #V, 1)
|
||||
The gradient of the function at x
|
||||
Here, we use the flatten the gradient
|
||||
The flatten process asks the all x coordinates to be first
|
||||
then all y cooridnates to be the second.
|
||||
- c: float
|
||||
The coefficient for armijo condition
|
||||
- alpha: float
|
||||
The current step size
|
||||
|
||||
Output:
|
||||
- condition: bool
|
||||
True if the armijio condition is satisfied
|
||||
"""
|
||||
return f_x1 <= f_x + c*alpha*np.dot(p,grad)
|
||||
|
||||
def equilibrium_convergence_report_GD(solid, v_init, n_steps, step_size, thresh=1e-3):
|
||||
'''
|
||||
Finds the equilibrium by minimizing the total energy using gradient descent.
|
||||
|
||||
Input:
|
||||
- solid : an elastic solid to optimize
|
||||
- v_init : the initial guess for the equilibrium position
|
||||
- n_step : number of optimization steps
|
||||
- step_size : scaling factor of the gradient when taking the step
|
||||
- thresh : threshold to stop the optimization process on the gradient's magnitude
|
||||
|
||||
Ouput:
|
||||
- report : a dictionary containing various quantities of interest
|
||||
'''
|
||||
|
||||
solid.update_def_shape(v_init)
|
||||
|
||||
energies_el = np.zeros(shape=(n_steps+1,))
|
||||
energies_ext = np.zeros(shape=(n_steps+1,))
|
||||
residuals = np.zeros(shape=(n_steps+1,))
|
||||
times = np.zeros(shape=(n_steps+1,))
|
||||
step_sizes = np.zeros(shape=(n_steps,))
|
||||
|
||||
energies_el[0] = solid.energy_el
|
||||
energies_ext[0] = solid.energy_ext
|
||||
residuals[0] = np.linalg.norm((solid.f + solid.f_ext)[solid.free_idx, :])
|
||||
idx_stop = n_steps
|
||||
|
||||
energy_tot_prev = energies_el[0] + energies_ext[0]
|
||||
|
||||
t_start = time.time()
|
||||
for i in range(n_steps):
|
||||
## TODO: Find the descent direction
|
||||
## descent_dir has shape (#v, 3)
|
||||
descent_dir = (solid.f + solid.f_ext)
|
||||
|
||||
|
||||
step_size_tmp = step_size
|
||||
max_l_iter = 20
|
||||
for l_iter in range(max_l_iter):
|
||||
step_size_tmp *= 0.5
|
||||
solid.displace(step_size_tmp * descent_dir)
|
||||
|
||||
## TODO: Check if the armijo rule is satisfied
|
||||
## energy_tot_tmp is the current total energy
|
||||
## armijo is a boolean that says whether the condition is satisfied
|
||||
energy_tot_tmp = solid.energy_ext + solid.energy_el
|
||||
grad_tmp = -descent_dir
|
||||
armijo = energy_tot_tmp < energy_tot_prev + thresh * step_size_tmp * ((descent_dir*grad_tmp).sum())
|
||||
|
||||
if armijo or l_iter == max_l_iter-1:
|
||||
break
|
||||
else:
|
||||
solid.displace(-step_size_tmp * descent_dir)
|
||||
step_sizes[i] = step_size_tmp
|
||||
|
||||
# Measure the force residuals
|
||||
energies_el[i+1] = solid.energy_el
|
||||
energies_ext[i+1] = solid.energy_ext
|
||||
residuals[i+1] = np.linalg.norm((solid.f + solid.f_ext)[solid.free_idx, :])
|
||||
energy_tot_prev = energy_tot_tmp
|
||||
|
||||
if residuals[i+1] < thresh:
|
||||
energies_el[i+1:] = energies_el[i+1]
|
||||
energies_ext[i+1:] = energies_ext[i+1]
|
||||
residuals[i+1:] = residuals[i+1]
|
||||
idx_stop = i
|
||||
break
|
||||
|
||||
times[i+1] = time.time() - t_start
|
||||
|
||||
report = {}
|
||||
report['energies_el'] = energies_el
|
||||
report['energies_ext'] = energies_ext
|
||||
report['residuals'] = residuals
|
||||
report['times'] = times
|
||||
report['idx_stop'] = idx_stop
|
||||
report['step_sizes'] = step_sizes
|
||||
|
||||
return report
|
||||
|
||||
|
||||
def equilibrium_convergence_report_BFGS(solid, v_init, n_steps, step_size, thresh=1e-3):
|
||||
'''
|
||||
Finds the equilibrium by minimizing the total energy using BFGS.
|
||||
|
||||
Input:
|
||||
- solid : an elastic solid to optimize
|
||||
- v_init : the initial guess for the equilibrium position
|
||||
- n_step : number of optimization steps
|
||||
- step_size : scaling factor of the direction when taking the step
|
||||
- thresh : threshold to stop the optimization process on the gradient's magnitude
|
||||
|
||||
Ouput:
|
||||
- report : a dictionary containing various quantities of interest
|
||||
'''
|
||||
|
||||
solid.update_def_shape(v_init)
|
||||
|
||||
energies_el = np.zeros(shape=(n_steps+1,))
|
||||
energies_ext = np.zeros(shape=(n_steps+1,))
|
||||
residuals = np.zeros(shape=(n_steps+1,))
|
||||
times = np.zeros(shape=(n_steps+1,))
|
||||
energies_el[0] = solid.energy_el
|
||||
energies_ext[0] = solid.energy_ext
|
||||
## TODO: Collect free vertex positions
|
||||
## grad_tmp is the current flattened gradient of the total energy
|
||||
## with respect to the free vertices
|
||||
grad_tmp = - (solid.f + solid.f_ext)[solid.free_idx,:].reshape(-1,1)
|
||||
residuals[0] = np.linalg.norm(grad_tmp)
|
||||
idx_stop = n_steps
|
||||
|
||||
energy_tot_prev = energies_el[0] + energies_ext[0]
|
||||
|
||||
|
||||
## TODO: Collect free vertex positions
|
||||
## v_tmp are the current flattened free vertices
|
||||
v_tmp = solid.v_def[solid.free_idx,:].reshape(-1,1)
|
||||
dir_zeros = np.zeros_like(solid.v_def)
|
||||
invB_prev = np.eye(v_tmp.shape[0])
|
||||
|
||||
t_start = time.time()
|
||||
for i in range(n_steps):
|
||||
|
||||
dir_tmp = - invB_prev @ grad_tmp
|
||||
dir_zeros[solid.free_idx, :] = dir_tmp.reshape(-1, 3)
|
||||
|
||||
step_size_tmp = step_size
|
||||
max_l_iter = 20
|
||||
for l_iter in range(max_l_iter):
|
||||
step_size_tmp *= 0.5
|
||||
solid.displace(step_size_tmp * dir_zeros)
|
||||
|
||||
## TODO: Check if the armijo rule is satisfied
|
||||
## energy_tot_tmp is the current total energy
|
||||
## armijo is a boolean that says whether the condition is satisfied
|
||||
energy_tot_tmp = solid.energy_el + solid.energy_ext
|
||||
armijo = energy_tot_tmp < energy_tot_prev + thresh * step_size_tmp*((dir_tmp*grad_tmp).sum())
|
||||
|
||||
if armijo or l_iter == max_l_iter-1:
|
||||
break
|
||||
else:
|
||||
solid.displace(-step_size_tmp * dir_zeros)
|
||||
|
||||
## TODO: Update all quantities
|
||||
## v_new are the new flattened free vertices
|
||||
## grad_new is the new flattened gradient of the total energy
|
||||
## with respect to the free vertices
|
||||
v_new = solid.v_def[solid.free_idx,:].reshape(-1,1)
|
||||
grad_new = - (solid.f+solid.f_ext)[solid.free_idx,:].reshape(-1,1)
|
||||
invB_prev = compute_inverse_approximate_hessian_matrix(v_new - v_tmp,
|
||||
grad_new - grad_tmp,
|
||||
invB_prev)
|
||||
v_tmp = v_new.copy()
|
||||
grad_tmp = grad_new.copy()
|
||||
|
||||
energies_el[i+1] = solid.energy_el
|
||||
energies_ext[i+1] = solid.energy_ext
|
||||
residuals[i+1] = np.linalg.norm(grad_tmp)
|
||||
|
||||
if residuals[i+1] < thresh:
|
||||
residuals[i+1:] = residuals[i+1]
|
||||
energies_el[i+1:] = energies_el[i+1]
|
||||
energies_ext[i+1:] = energies_ext[i+1]
|
||||
idx_stop = i
|
||||
break
|
||||
|
||||
times[i+1] = time.time() - t_start
|
||||
|
||||
report = {}
|
||||
report['energies_el'] = energies_el
|
||||
report['energies_ext'] = energies_ext
|
||||
report['residuals'] = residuals
|
||||
report['times'] = times
|
||||
report['idx_stop'] = idx_stop
|
||||
|
||||
return report
|
||||
|
||||
def equilibrium_convergence_report_NCG(solid, v_init, n_steps, thresh=1e-3):
|
||||
'''
|
||||
Finds the equilibrium by minimizing the total energy using Newton CG.
|
||||
|
||||
Input:
|
||||
- solid : an elastic solid to optimize
|
||||
- v_init : the initial guess for the equilibrium position
|
||||
- n_step : number of optimization steps
|
||||
- thresh : threshold to stop the optimization process on the gradient's magnitude
|
||||
|
||||
Ouput:
|
||||
- report : a dictionary containing various quantities of interest
|
||||
'''
|
||||
|
||||
solid.update_def_shape(v_init)
|
||||
|
||||
energies_el = np.zeros(shape=(n_steps+1,))
|
||||
energies_ext = np.zeros(shape=(n_steps+1,))
|
||||
residuals = np.zeros(shape=(n_steps+1,))
|
||||
times = np.zeros(shape=(n_steps+1,))
|
||||
energies_el[0] = solid.energy_el
|
||||
energies_ext[0] = solid.energy_ext
|
||||
residuals[0] = np.linalg.norm((solid.f + solid.f_ext)[solid.free_idx, :])
|
||||
idx_stop = n_steps
|
||||
|
||||
t_start = time.time()
|
||||
for i in range(n_steps):
|
||||
# Take a Newton step
|
||||
solid.equilibrium_step()
|
||||
|
||||
# Measure the force residuals
|
||||
energies_el[i+1] = solid.energy_el
|
||||
energies_ext[i+1] = solid.energy_ext
|
||||
residuals[i+1] = np.linalg.norm((solid.f + solid.f_ext)[solid.free_idx, :])
|
||||
|
||||
if residuals[i+1] < thresh:
|
||||
residuals[i+1:] = residuals[i+1]
|
||||
energies_el[i+1:] = energies_el[i+1]
|
||||
energies_ext[i+1:] = energies_ext[i+1]
|
||||
idx_stop = i
|
||||
break
|
||||
|
||||
times[i+1] = time.time() - t_start
|
||||
|
||||
report = {}
|
||||
report['energies_el'] = energies_el
|
||||
report['energies_ext'] = energies_ext
|
||||
report['residuals'] = residuals
|
||||
report['times'] = times
|
||||
report['idx_stop'] = idx_stop
|
||||
|
||||
return report
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
def fd_validation_ext(solid):
|
||||
epsilons = np.logspace(-9,-3,100)
|
||||
perturb_global = np.random.uniform(-1e-3, 1e-3, size=solid.v_def.shape)
|
||||
solid.displace(perturb_global)
|
||||
v_def = solid.v_def.copy()
|
||||
perturb = np.random.uniform(-1, 1, size=solid.v_def.shape)
|
||||
errors = []
|
||||
for eps in epsilons:
|
||||
# Back to original
|
||||
solid.update_def_shape(v_def)
|
||||
grad = np.zeros(solid.f_ext.shape)
|
||||
grad[solid.free_idx] = -solid.f_ext.copy()[solid.free_idx]
|
||||
an_delta_E = (grad*perturb).sum()
|
||||
|
||||
# One step forward
|
||||
solid.displace(perturb * eps)
|
||||
E1 = solid.energy_ext.copy()
|
||||
|
||||
# Two steps backward
|
||||
solid.displace(-2*perturb * eps)
|
||||
E2 = solid.energy_ext.copy()
|
||||
|
||||
# Compute error
|
||||
fd_delta_E = (E1 - E2)/(2*eps)
|
||||
errors.append(abs(fd_delta_E - an_delta_E)/abs(an_delta_E))
|
||||
plt.loglog(epsilons, errors)
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
def fd_validation_elastic(solid):
|
||||
epsilons = np.logspace(-9,-3,100)
|
||||
perturb_global = np.random.uniform(-1e-3, 1e-3, size=solid.v_def.shape)
|
||||
solid.displace(perturb_global)
|
||||
|
||||
v_def = solid.v_def.copy()
|
||||
solid.make_elastic_forces()
|
||||
|
||||
perturb = np.random.uniform(-1, 1, size=solid.v_def.shape)
|
||||
errors = []
|
||||
for eps in epsilons:
|
||||
# Back to original
|
||||
solid.update_def_shape(v_def)
|
||||
solid.make_elastic_forces()
|
||||
grad = np.zeros(solid.f.shape)
|
||||
grad[solid.free_idx] = -solid.f.copy()[solid.free_idx]
|
||||
an_delta_E = (grad*perturb).sum()
|
||||
|
||||
# One step forward
|
||||
solid.displace(perturb * eps)
|
||||
E1 = solid.energy_el.copy()
|
||||
|
||||
# Two steps backward
|
||||
solid.displace(-2*perturb * eps)
|
||||
E2 = solid.energy_el.copy()
|
||||
|
||||
# Compute error
|
||||
fd_delta_E = (E1 - E2)/(2*eps)
|
||||
errors.append(abs(fd_delta_E - an_delta_E)/abs(an_delta_E))
|
||||
solid.displace(perturb * eps)
|
||||
|
||||
plt.loglog(epsilons, errors)
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
def fd_validation_elastic_differentials(solid):
|
||||
epsilons = np.logspace(-9, 3,500)
|
||||
perturb_global = 1e-3*np.random.uniform(-1., 1., size=solid.v_def.shape)
|
||||
solid.displace(perturb_global)
|
||||
|
||||
v_def = solid.v_def.copy()
|
||||
|
||||
perturb = np.random.uniform(-1, 1, size=solid.v_def.shape)
|
||||
errors = []
|
||||
for eps in epsilons:
|
||||
# Back to original
|
||||
solid.update_def_shape(v_def)
|
||||
perturb_0s = np.zeros_like(perturb)
|
||||
perturb_0s[solid.free_idx] = perturb[solid.free_idx]
|
||||
an_df = solid.compute_force_differentials(perturb_0s)[solid.free_idx, :]
|
||||
an_df_full = np.zeros(solid.f.shape)
|
||||
an_df_full[solid.free_idx] = an_df.copy()
|
||||
|
||||
# One step forward
|
||||
solid.displace(perturb * eps)
|
||||
f1 = solid.f[solid.free_idx, :]
|
||||
f1_full = np.zeros(solid.f.shape)
|
||||
f1_full[solid.free_idx] = f1
|
||||
|
||||
# Two steps backward
|
||||
solid.displace(-2*perturb * eps)
|
||||
f2 = solid.f[solid.free_idx, :]
|
||||
f2_full = np.zeros(solid.f.shape)
|
||||
f2_full[solid.free_idx] = f2
|
||||
|
||||
# Compute error
|
||||
fd_delta_f = (f1_full - f2_full)/(2*eps)
|
||||
norm_an_df = np.linalg.norm(an_df_full)
|
||||
norm_error = np.linalg.norm(an_df_full - fd_delta_f)
|
||||
errors.append(norm_error/norm_an_df)
|
||||
|
||||
plt.loglog(epsilons, errors)
|
||||
plt.grid()
|
||||
plt.show()
|
163
cs457-gc/assignment_2_2/src/elasticenergy.py
Normal file
@@ -0,0 +1,163 @@
|
||||
import numpy as np
|
||||
from numpy.core.einsumfunc import einsum
|
||||
from numpy.core.fromnumeric import swapaxes
|
||||
|
||||
class ElasticEnergy:
|
||||
def __init__(self, young, poisson):
|
||||
'''
|
||||
Input:
|
||||
- young : Young's modulus [Pa]
|
||||
- poisson : Poisson ratio
|
||||
'''
|
||||
self.young = young
|
||||
self.poisson = poisson
|
||||
self.lbda = young * poisson / ((1 + poisson) * (1 - 2 * poisson))
|
||||
self.mu = young / (2 * (1 + poisson))
|
||||
|
||||
self.psi = None
|
||||
self.E = None
|
||||
self.P = None
|
||||
|
||||
self.dE = None
|
||||
self.dP = None
|
||||
|
||||
def make_energy_density(self, jac):
|
||||
'''
|
||||
This method computes the energy density at each tetrahedron (#t,),
|
||||
and stores the result in self.psi
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- psi : energy density per tet (#t,)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_strain_tensor(self, jac):
|
||||
'''
|
||||
This method computes the strain tensor (#t, 3, 3), and stores it in self.E
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- E : strain induced by the deformation (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_piola_kirchhoff_stress_tensor(self, jac):
|
||||
'''
|
||||
This method computes the stress tensor (#t, 3, 3), and stores it in self.P
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- P : stress tensor induced by the deformation (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_differential_strain_tensor(self, jac, dJac):
|
||||
'''
|
||||
This method computes the differential of strain tensor (#t, 3, 3),
|
||||
and stores it in self.dE
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
- dJac : differential of the jacobian of the deformation (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- dE : differential of the strain tensor (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_differential_piola_kirchhoff_stress_tensor(self, jac, dJac):
|
||||
'''
|
||||
This method computes the differential of the stress tensor (#t, 3, 3), and stores it in self.dP
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
- dJac : differential of the jacobian of the deformation (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- dP : differential of the stress tensor (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
class LinearElasticEnergy(ElasticEnergy):
|
||||
def __init__(self, young, poisson):
|
||||
super().__init__(young, poisson)
|
||||
|
||||
def make_energy_density(self, jac):
|
||||
fa = self.mu * np.einsum("ijk,ijk->i",self.E, self.E)
|
||||
fb = self.lbda/2.0 * np.einsum('ijj->i' ,self.E)**2
|
||||
self.psi = fa + fb
|
||||
|
||||
def make_strain_tensor(self, jac):
|
||||
self.E = (jac+np.transpose(jac,axes=(0,2,1)))/2.0 - np.identity(3)
|
||||
|
||||
def make_piola_kirchhoff_stress_tensor(self, jac):
|
||||
fa = 2.0*self.mu*self.E
|
||||
fb = self.lbda* np.einsum('i,jk->ijk',np.einsum('ijj->i',self.E), np.identity(3))
|
||||
self.P = fa + fb
|
||||
|
||||
def make_differential_strain_tensor(self, jac, dJac):
|
||||
self.dE = (dJac+np.transpose(dJac,axes=(0,2,1)))/2.0
|
||||
|
||||
def make_differential_piola_kirchhoff_stress_tensor(self, jac, dJac):
|
||||
fa = 2.0*self.mu*self.dE
|
||||
fb = self.lbda* np.einsum("i,jk->ijk",np.trace(self.dE, axis1=1,axis2=2), np.identity(3))
|
||||
self.dP = fa + fb
|
||||
|
||||
class NeoHookeanElasticEnergy(ElasticEnergy):
|
||||
def __init__(self, young, poisson):
|
||||
super().__init__(young, poisson)
|
||||
self.logJ = None
|
||||
self.Finv = None
|
||||
|
||||
def make_energy_density(self, jac):
|
||||
i1 = np.einsum('ijk,ijk->i',jac,jac)
|
||||
j = np.log(np.linalg.det(jac))
|
||||
fa = self.mu/2.0 * (i1-3 - 2*j)
|
||||
fb = self.lbda/2.0 * j**2
|
||||
self.psi = fa + fb
|
||||
|
||||
def make_strain_tensor(self, jac):
|
||||
pass
|
||||
|
||||
def make_piola_kirchhoff_stress_tensor(self, jac):
|
||||
'''
|
||||
Additional updated attributes:
|
||||
- logJ ; log of the determinant of the jacobians (#t,)
|
||||
- Finv : inverse of the jacobians (#t, 3, 3)
|
||||
'''
|
||||
self.logJ = np.log(np.linalg.det(jac))
|
||||
self.Finv = np.linalg.inv(jac)
|
||||
FinvT = np.transpose(self.Finv,axes=(0,2,1))
|
||||
fa = self.mu * (jac - FinvT)
|
||||
fb = self.lbda * np.einsum("i,ijk->ijk",self.logJ, FinvT)
|
||||
self.P = fa +fb
|
||||
|
||||
def make_differential_strain_tensor(self, jac, dJac):
|
||||
pass
|
||||
|
||||
def make_differential_piola_kirchhoff_stress_tensor(self, jac, dJac):
|
||||
self.logJ = np.log(np.linalg.det(jac))
|
||||
self.Finv = np.linalg.inv(jac)
|
||||
FinvT = np.transpose(self.Finv,axes=(0,2,1))
|
||||
dFT = np.transpose(dJac,axes=(0,2,1))
|
||||
fa = self.mu * dJac
|
||||
fb = np.einsum("i,ijk->ijk",(self.mu - self.lbda * self.logJ),FinvT @ dFT @ FinvT)
|
||||
fc = self.lbda * np.einsum("i,ijk->ijk",np.trace(self.Finv @ dJac, axis1=1,axis2=2),FinvT)
|
||||
self.dP = fa + fb + fc
|
404
cs457-gc/assignment_2_2/src/elasticsolid.py
Normal file
@@ -0,0 +1,404 @@
|
||||
import numpy as np
|
||||
from numpy import linalg
|
||||
from scipy import sparse
|
||||
from Utils import *
|
||||
import igl
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
# ELASTIC SOLID CLASS
|
||||
# -----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
class ElasticSolid(object):
|
||||
|
||||
def __init__(self, v_rest, t, ee, rho=1, pin_idx=[], f_mass=None):
|
||||
'''
|
||||
Input:
|
||||
- v_rest : position of the vertices of the mesh (#v, 3)
|
||||
- t : indices of the element's vertices (#t, 4)
|
||||
- ee : elastic energy object that can be found in elasticenergy.py
|
||||
- rho : mass per unit volume [kg.m-3]
|
||||
- pin_idx : list or np array of vertex indices to pin
|
||||
- f_mass : external force per unit mass (3,) [N.kg-1]
|
||||
'''
|
||||
|
||||
self.v_rest = v_rest.copy()
|
||||
self.v_def = v_rest.copy()
|
||||
self.t = t
|
||||
self.ee = ee
|
||||
self.rho = rho
|
||||
self.pin_idx = np.array(pin_idx)
|
||||
self.f_mass = f_mass.copy()
|
||||
self.free_idx = None
|
||||
self.pin_mask = None
|
||||
|
||||
self.W0 = None
|
||||
self.Dm = None
|
||||
self.Bm = None
|
||||
self.rest_barycenters = None
|
||||
|
||||
self.W = None
|
||||
self.Ds = None
|
||||
self.F = None
|
||||
self.def_barycenters = None
|
||||
|
||||
self.energy_el = None
|
||||
self.energy_ext = None
|
||||
|
||||
self.f = None
|
||||
self.f_vol = None
|
||||
self.f_ext = None
|
||||
|
||||
self.make_free_indices_and_pin_mask()
|
||||
self.update_rest_shape(self.v_rest)
|
||||
self.update_def_shape(self.v_def)
|
||||
|
||||
## Utils ##
|
||||
|
||||
def vertex_tet_sum(self, data):
|
||||
'''
|
||||
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 : np array of shape (#t,) or (4*#t,)
|
||||
|
||||
Output:
|
||||
- data_sum : np array of shape (#v,), containing the summed data
|
||||
'''
|
||||
i = self.t.flatten('F') # (4*#t,)
|
||||
j = np.arange(len(self.t)) # (#t,)
|
||||
j = np.tile(j, 4) # (4*#t,)
|
||||
|
||||
if len(data) == len(self.t):
|
||||
data = data[j]
|
||||
|
||||
# Has shape (#v, #t)
|
||||
m = sparse.coo_matrix((data, (i, j)), (len(self.v_rest), len(self.t)))
|
||||
return np.array(m.sum(axis=1)).flatten()
|
||||
|
||||
## Precomputation ##
|
||||
|
||||
def make_free_indices_and_pin_mask(self):
|
||||
'''
|
||||
Should list all the free indices and the pin mask.
|
||||
|
||||
Updated attributes:
|
||||
- free_index : np array of shape (#free_vertices,) containing the list of unpinned vertices
|
||||
- pin_mask : np array of shape (#v, 1) containing 1 at free vertex indices and 0 at pinned vertex indices
|
||||
'''
|
||||
self.pin_mask = np.ones((self.v_rest.shape[0],1))
|
||||
self.free_idx = np.arange(0,self.v_rest.shape[0])
|
||||
if(self.pin_idx.shape[0]<=0):
|
||||
return
|
||||
self.pin_mask[self.pin_idx] = 0
|
||||
self.free_idx = np.where(self.pin_mask==1)[0]
|
||||
|
||||
|
||||
|
||||
## Methods related to rest quantities ##
|
||||
|
||||
def make_rest_barycenters(self):
|
||||
'''
|
||||
Construct the barycenters of the undeformed configuration
|
||||
|
||||
Updated attributes:
|
||||
- rest_barycenters : np array of shape (#t, 3) containing the position of each tet's barycenter
|
||||
'''
|
||||
self.rest_barycenters = np.einsum("ijk->ik",self.v_rest[self.t])/4
|
||||
|
||||
def make_rest_shape_matrices(self):
|
||||
'''
|
||||
Construct Ds that has shape (#t, 3, 3), and its inverse Bm
|
||||
|
||||
Updated attributes:
|
||||
- Dm : np array of shape (#t, 3, 3) containing the shape matrix of each tet
|
||||
- Bm : np array of shape (#t, 3, 3) containing the inverse shape matrix of each tet
|
||||
'''
|
||||
tv = self.v_rest[self.t]
|
||||
|
||||
tva = tv[:,:3,:]
|
||||
tvb = tv[:,3,:].reshape((self.t.shape[0],1,3))
|
||||
tvb= np.repeat(tvb, 3, axis=1)
|
||||
|
||||
tvs = tva - tvb
|
||||
tvsf = np.transpose(tvs,(0,2,1))
|
||||
|
||||
self.Dm = tvsf
|
||||
self.Bm = np.linalg.inv(tvsf)
|
||||
|
||||
def update_rest_shape(self, v_rest):
|
||||
'''
|
||||
Updates the vertex position, the shape matrices Dm and Bm, the volumes W0,
|
||||
and the mass matrix at rest
|
||||
|
||||
Input:
|
||||
- v_rest : position of the vertices of the mesh at rest state (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- v_rest : np array of shape (#v, 3) containing the position of each vertex at rest
|
||||
- W0 : np array of shape (#t,) containing the signed volume of each tet
|
||||
'''
|
||||
self.v_rest = v_rest
|
||||
self.make_rest_barycenters()
|
||||
self.make_rest_shape_matrices()
|
||||
self.W0 = -np.linalg.det(self.Dm)/6
|
||||
self.update_def_shape(self.v_def)
|
||||
self.make_volumetric_and_external_forces()
|
||||
|
||||
## Methods related to deformed quantities ##
|
||||
|
||||
def make_def_barycenters(self):
|
||||
'''
|
||||
Construct the barycenters of the deformed configuration
|
||||
|
||||
Updated attributes:
|
||||
- def_barycenters : np array of shape (#t, 3) containing the position of each tet's barycenter
|
||||
'''
|
||||
self.def_barycenters = np.einsum("ijk->ik",self.v_def[self.t])/4
|
||||
|
||||
def make_def_shape_matrices(self):
|
||||
'''
|
||||
Construct Ds that has shape (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- Ds : np array of shape (#t, 3, 3) containing the shape matrix of each tet
|
||||
'''
|
||||
tv = self.v_def[self.t]
|
||||
|
||||
tva = tv[:,:3,:]
|
||||
tvb = tv[:,3,:].reshape((self.t.shape[0],1,3))
|
||||
tvb= np.repeat(tvb, 3, axis=1)
|
||||
|
||||
tvs = tva - tvb
|
||||
tvsf = np.transpose(tvs,(0,2,1))
|
||||
|
||||
self.Ds = tvsf
|
||||
|
||||
def make_jacobians(self):
|
||||
'''
|
||||
Compute the current Jacobian of the deformation
|
||||
|
||||
Updated attributes:
|
||||
- F : np array of shape (#t, 3, 3) containing Jacobian of the deformation in each tet
|
||||
'''
|
||||
self.F = self.Ds @ self.Bm # <=> np.einsum("lij,ljk->lik",self.Ds,self.Bm)
|
||||
|
||||
def update_def_shape(self, v_def):
|
||||
'''
|
||||
Updates the vertex position, the Jacobian of the deformation, and the
|
||||
resulting elastic forces.
|
||||
|
||||
Input:
|
||||
- v_def : position of the vertices of the mesh (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- v_def : np array of shape (#v, 3) containing the position of each vertex after deforming the solid
|
||||
- W : np array of shape (#t,) containing the signed volume of each tet
|
||||
'''
|
||||
self.v_def = self.v_rest
|
||||
self.v_def[self.free_idx] = v_def[self.free_idx]
|
||||
self.make_def_barycenters()
|
||||
self.make_def_shape_matrices()
|
||||
self.W = -np.linalg.det(self.Ds)/6
|
||||
self.make_jacobians()
|
||||
if(self.f_vol is None):
|
||||
self.make_volumetric_and_external_forces()
|
||||
self.make_elastic_forces()
|
||||
self.make_elastic_energy()
|
||||
self.make_external_energy()
|
||||
|
||||
def displace(self, v_disp):
|
||||
'''
|
||||
Displace the whole mesh so that v_def += v_disp
|
||||
|
||||
Input:
|
||||
- v_disp : displacement of the vertices of the mesh (#v, 3)
|
||||
'''
|
||||
self.update_def_shape(self.v_def + v_disp)
|
||||
|
||||
## Energies ##
|
||||
|
||||
def make_elastic_energy(self):
|
||||
'''
|
||||
This updates the elastic energy
|
||||
|
||||
Updated attributes:
|
||||
- energy_el : elastic energy of the system [J]
|
||||
'''
|
||||
self.ee.make_strain_tensor(self.F)
|
||||
self.ee.make_energy_density(self.F)
|
||||
self.energy_el = np.sum(self.W0 * self.ee.psi)
|
||||
|
||||
def make_external_energy(self):
|
||||
'''
|
||||
This computes the external energy potential
|
||||
|
||||
Updated attributes:
|
||||
- energy_ext : postential energy due to external forces [J]
|
||||
'''
|
||||
dx = self.def_barycenters - self.rest_barycenters
|
||||
ifv = np.einsum('i,ij -> ij', self.W0, self.f_vol)
|
||||
self.energy_ext = - np.einsum("i,ij,ij->",self.W0, self.f_vol, dx)
|
||||
|
||||
## Forces ##
|
||||
|
||||
def make_elastic_forces(self):
|
||||
'''
|
||||
This method updates the elastic forces stored in self.f (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- f : elastic forces per vertex (#v, 3)
|
||||
- ee : elastic energy, some attributes should be updated
|
||||
'''
|
||||
self.ee.make_strain_tensor(self.F)
|
||||
self.ee.make_piola_kirchhoff_stress_tensor(self.F)
|
||||
tdm = np.transpose(self.Bm,(0,2,1))
|
||||
ptdm = self.ee.P @ tdm
|
||||
f123 = -np.einsum("i,ijk->ikj",self.W0,ptdm )
|
||||
f4 = -f123[:,0] - f123[:,1] - f123[:,2]
|
||||
H = np.hstack((f123,f4[:,None]))
|
||||
|
||||
x = self.vertex_tet_sum(H[:,:,0].flatten('F'))
|
||||
y = self.vertex_tet_sum(H[:,:,1].flatten('F'))
|
||||
z = self.vertex_tet_sum(H[:,:,2].flatten('F'))
|
||||
|
||||
self.f = np.hstack((x[:,None],y[:,None],z[:,None]))
|
||||
|
||||
def make_volumetric_and_external_forces(self):
|
||||
'''
|
||||
Convert force per unit mass to volumetric forces, then distribute
|
||||
the forces to the vertices of the mesh.
|
||||
|
||||
Updated attributes:
|
||||
- f_vol : np array of shape (#t, 3) external force per unit volume acting on the tets
|
||||
- f_ext : np array of shape (#v, 3) external force acting on the vertices
|
||||
'''
|
||||
mpv = self.f_mass*self.rho
|
||||
self.f_vol = np.ones((self.W0.shape[0],1)) * mpv
|
||||
|
||||
ifv = np.einsum('i,ij -> ij', self.W0, self.f_vol)
|
||||
|
||||
f_ext_x = self.vertex_tet_sum(ifv[:,0])
|
||||
f_ext_y = self.vertex_tet_sum(ifv[:,1])
|
||||
f_ext_z = self.vertex_tet_sum(ifv[:,2])
|
||||
|
||||
self.f_ext = np.stack((f_ext_x,f_ext_y,f_ext_z),axis=1) / 4.0
|
||||
|
||||
## Force Differentials
|
||||
|
||||
def compute_force_differentials(self, v_disp):
|
||||
'''
|
||||
This computes the differential of the force given a displacement dx,
|
||||
where df = df/dx|x . dx = - K(x).dx. Where K(x) is the stiffness matrix (or Hessian)
|
||||
of the solid. Note that the implementation doesn't need to construct the stiffness matrix explicitly.
|
||||
|
||||
Input:
|
||||
- v_disp : displacement of the vertices of the mesh (#v, 3)
|
||||
|
||||
Output:
|
||||
- df : force differentials at the vertices of the mesh (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- ee : elastic energy, some attributes should be updated
|
||||
'''
|
||||
|
||||
# First compute the differential of the Jacobian
|
||||
tv = v_disp[self.t]
|
||||
tva = tv[:,:3,:]
|
||||
tvb = tv[:,3,:].reshape((-1,1,3))
|
||||
|
||||
tvb= np.repeat(tvb, 3, axis=1)
|
||||
|
||||
tvs = tva - tvb
|
||||
tvsf = np.transpose(tvs,(0,2,1))
|
||||
|
||||
dDs = tvsf
|
||||
dF = dDs @ self.Bm
|
||||
|
||||
# Then update differential quantities in self.ee
|
||||
self.ee.make_differential_strain_tensor(self.F,dF)
|
||||
self.ee.make_differential_piola_kirchhoff_stress_tensor(self.F,dF)
|
||||
|
||||
# Compute the differential of the forces
|
||||
tdm = np.transpose(self.Bm,(0,2,1))
|
||||
ptdm = self.ee.dP @ tdm
|
||||
f123 = -np.einsum("i,ijk->ikj",self.W0,ptdm )
|
||||
f4 = -f123[:,0] - f123[:,1] - f123[:,2]
|
||||
H = np.hstack((f123,f4[:,None]))
|
||||
|
||||
x = self.vertex_tet_sum(H[:,:,0].flatten('F'))
|
||||
y = self.vertex_tet_sum(H[:,:,1].flatten('F'))
|
||||
z = self.vertex_tet_sum(H[:,:,2].flatten('F'))
|
||||
|
||||
return np.hstack((x[:,None],y[:,None],z[:,None]))
|
||||
|
||||
def equilibrium_step(self, step_size_init = 2, max_l_iter = 20, c1 = 1e-4):
|
||||
'''
|
||||
This function displaces the whole solid to the next deformed configuration
|
||||
using a Newton-CG step.
|
||||
|
||||
Updated attributes:
|
||||
- LHS : The hessian vector product
|
||||
- RHS : Right hand side for the conjugate gradient linear solve
|
||||
Other than them, only attributes updated by displace(self, v_disp) should be changed
|
||||
'''
|
||||
|
||||
# Define LHS
|
||||
def LHS(dx):
|
||||
'''
|
||||
Should implement the Hessian-Vector Product L(dx), and take care of pinning constraints
|
||||
as described in the handout.
|
||||
'''
|
||||
if len(dx.shape)==1:
|
||||
dx = dx.reshape((-1,3))
|
||||
|
||||
if (dx.shape[0] < self.v_rest.shape[0]):
|
||||
dxf = np.zeros((self.v_rest.shape[0],3))
|
||||
dxf[self.free_idx] = dx
|
||||
dx = dxf
|
||||
|
||||
res = self.compute_force_differentials(dx)
|
||||
|
||||
return res[self.free_idx].flatten()
|
||||
|
||||
self.LHS = LHS # Save to class for testing
|
||||
|
||||
# Define RHS
|
||||
RHS = - (self.f + self.f_ext)[self.free_idx]
|
||||
|
||||
self.RHS = RHS # Save to class for testing
|
||||
|
||||
# Use conjugate gradient to find a descent direction
|
||||
# (see conjugate_gradient in Utils.py)
|
||||
dx_CG = conjugate_gradient(LHS,RHS.flatten()) # shape (#v, 3)
|
||||
|
||||
|
||||
# Run line search on the direction
|
||||
step_size = step_size_init
|
||||
ft = self.f + self.f_ext
|
||||
energy_tot_prev = self.energy_el + self.energy_ext
|
||||
for l_iter in range(max_l_iter):
|
||||
step_size *= 0.5 # DO NOT CHANGE
|
||||
dx_search = dx_CG * step_size
|
||||
self.displace(dx_search)
|
||||
|
||||
# Current force norm for unpinned vertices
|
||||
f_tmp = (self.f + self.f_ext)
|
||||
f_tmp[self.free_idx] = 0
|
||||
g = np.linalg.norm(f_tmp)
|
||||
|
||||
energy_tot_tmp = self.energy_el + self.energy_ext
|
||||
|
||||
#Make sure you only use the gradient of the unpinned vertices
|
||||
# USE parameter c1 = 1e-4 (from the function arguments) when you submit
|
||||
armijo = evaluate_armijo_rule(energy_tot_prev, energy_tot_tmp, dx_CG, -dx_CG, c1, step_size)
|
||||
|
||||
if armijo or l_iter == max_l_iter-1:
|
||||
print("Energy: " + str(energy_tot_tmp) + " Force norm: " + str(g) + " Line search Iters: " + str(l_iter))
|
||||
break
|
||||
else:
|
||||
self.displace(-dx_search)
|
BIN
cs457-gc/assignment_2_2/test/fd_linear_energy_elastic.png
Normal file
After Width: | Height: | Size: 460 KiB |
BIN
cs457-gc/assignment_2_2/test/fd_linear_energy_external.png
Normal file
After Width: | Height: | Size: 538 KiB |
BIN
cs457-gc/assignment_2_2/test/fd_neo_energy_elastic.png
Normal file
After Width: | Height: | Size: 532 KiB |
BIN
cs457-gc/assignment_2_2/test/fd_neo_energy_external.png
Normal file
After Width: | Height: | Size: 737 KiB |
BIN
cs457-gc/assignment_2_2/test/linear_bfgs_equilibrium.png
Normal file
After Width: | Height: | Size: 356 KiB |
BIN
cs457-gc/assignment_2_2/test/linear_energy_plot.png
Normal file
After Width: | Height: | Size: 324 KiB |
BIN
cs457-gc/assignment_2_2/test/linear_gd_equilibrium.png
Normal file
After Width: | Height: | Size: 429 KiB |
BIN
cs457-gc/assignment_2_2/test/neo_bfgs_equilibrium.png
Normal file
After Width: | Height: | Size: 613 KiB |
BIN
cs457-gc/assignment_2_2/test/neo_energy_plot.png
Normal file
After Width: | Height: | Size: 343 KiB |
BIN
cs457-gc/assignment_2_2/test/neo_gd_equilibrium.png
Normal file
After Width: | Height: | Size: 682 KiB |
114
cs457-gc/assignment_2_2/test/test.py
Normal file
@@ -0,0 +1,114 @@
|
||||
import time
|
||||
import pytest
|
||||
import json
|
||||
import sys
|
||||
import igl
|
||||
import numpy as np
|
||||
sys.path.append('../')
|
||||
sys.path.append('../src')
|
||||
from elasticsolid import *
|
||||
from elasticenergy import *
|
||||
eps = 1E-6
|
||||
|
||||
with open('test_data2.json', 'r') as infile:
|
||||
homework_datas = json.load(infile)
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[0])
|
||||
def test_linear_psi(data):
|
||||
young, poisson, F, psi_gt = data
|
||||
ee = LinearElasticEnergy(young, poisson)
|
||||
print(np.array(F).shape)
|
||||
ee.make_strain_tensor(np.array(F))
|
||||
ee.make_energy_density(np.array(F))
|
||||
assert np.linalg.norm(ee.psi - np.array(psi_gt)) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[1])
|
||||
def test_linear_strain(data):
|
||||
young, poisson, F, E_gt = data
|
||||
ee = LinearElasticEnergy(young, poisson)
|
||||
ee.make_strain_tensor(np.array(F))
|
||||
print(np.array(E_gt).shape, np.array(E_gt)[0])
|
||||
assert np.linalg.norm(ee.E - np.array(E_gt)) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[2])
|
||||
def test_linear_stress(data):
|
||||
young, poisson, F, P_gt = data
|
||||
ee = LinearElasticEnergy(young, poisson)
|
||||
ee.make_strain_tensor(np.array(F))
|
||||
ee.make_piola_kirchhoff_stress_tensor(np.array(F))
|
||||
assert np.linalg.norm(ee.P - np.array(P_gt)) < eps
|
||||
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[3])
|
||||
def test_neo_psi(data):
|
||||
young, poisson, F, psi_gt = data
|
||||
ee = NeoHookeanElasticEnergy(young, poisson)
|
||||
ee.make_energy_density(np.array(F))
|
||||
assert np.linalg.norm(ee.psi - np.array(psi_gt)) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[4])
|
||||
def test_neo_stress(data):
|
||||
young, poisson, F, P_gt, logJ_gt, Finv_gt = data
|
||||
ee = NeoHookeanElasticEnergy(young, poisson)
|
||||
ee.make_piola_kirchhoff_stress_tensor(np.array(F))
|
||||
assert np.linalg.norm(ee.P - np.array(P_gt)) < eps
|
||||
assert np.linalg.norm(ee.logJ - np.array(logJ_gt)) < eps
|
||||
assert np.linalg.norm(ee.Finv - np.array(Finv_gt)) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[5])
|
||||
def test_energy_el(data):
|
||||
etype, young, poisson, v, t, rho, pin_idx, force_mass, v_def, ee_gt = data
|
||||
if etype == "linear":
|
||||
ee = LinearElasticEnergy(young, poisson)
|
||||
else:
|
||||
ee = NeoHookeanElasticEnergy(young, poisson)
|
||||
|
||||
es = ElasticSolid(np.array(v), np.array(t), ee, rho=rho, pin_idx=np.array(pin_idx), f_mass=np.array(force_mass))
|
||||
es.update_def_shape(np.array(v_def))
|
||||
assert np.linalg.norm(es.energy_el - np.array(ee_gt)) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[6])
|
||||
def test_forces_el(data):
|
||||
etype, young, poisson, v, t, rho, pin_idx, force_mass, v_def, ef_gt = data
|
||||
if etype == "linear":
|
||||
ee = LinearElasticEnergy(young, poisson)
|
||||
else:
|
||||
ee = NeoHookeanElasticEnergy(young, poisson)
|
||||
|
||||
es = ElasticSolid(np.array(v), np.array(t), ee, rho=rho, pin_idx=np.array(pin_idx), f_mass=np.array(force_mass))
|
||||
es.update_def_shape(np.array(v_def))
|
||||
assert np.linalg.norm(es.f - np.array(ef_gt)) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[7])
|
||||
def test_energy_ext(data):
|
||||
etype, young, poisson, v, t, rho, pin_idx, force_mass, v_def, exte_gt = data
|
||||
if etype == "linear":
|
||||
ee = LinearElasticEnergy(young, poisson)
|
||||
else:
|
||||
ee = NeoHookeanElasticEnergy(young, poisson)
|
||||
|
||||
es = ElasticSolid(np.array(v), np.array(t), ee, rho=rho, pin_idx=np.array(pin_idx), f_mass=np.array(force_mass))
|
||||
es.update_def_shape(np.array(v_def))
|
||||
assert np.linalg.norm(es.energy_ext - np.array(exte_gt)) < eps
|
||||
|
||||
@pytest.mark.timeout(0.5)
|
||||
@pytest.mark.parametrize("data", homework_datas[8])
|
||||
def test_forces_ext(data):
|
||||
etype, young, poisson, v, t, rho, pin_idx, force_mass, v_def, fext_gt, fvol_gt = data
|
||||
if etype == "linear":
|
||||
ee = LinearElasticEnergy(young, poisson)
|
||||
else:
|
||||
ee = NeoHookeanElasticEnergy(young, poisson)
|
||||
|
||||
es = ElasticSolid(np.array(v), np.array(t), ee, rho=rho, pin_idx=np.array(pin_idx), f_mass=np.array(force_mass))
|
||||
es.update_def_shape(np.array(v_def))
|
||||
assert np.linalg.norm(es.f_ext - np.array(fext_gt)) < eps
|
||||
assert np.linalg.norm(es.f_vol - np.array(fvol_gt)) < eps
|
1
cs457-gc/assignment_2_2/test/test_data2.json
Normal file
BIN
cs457-gc/assignment_2_2/test_fd.pdf
Normal file
834
cs457-gc/assignment_2_3/data/ball.obj
Normal file
@@ -0,0 +1,834 @@
|
||||
v 3.06161699786838e-17 -7.49879891330929e-33 0.5
|
||||
v 3.06161699786838e-17 -7.49879891330929e-33 -0.5
|
||||
v 0.154508497187474 -3.78436673043416e-17 -0.475528258147577
|
||||
v 0.293892626146237 -7.19829327805997e-17 -0.404508497187474
|
||||
v 0.404508497187474 -9.90760072617093e-17 -0.293892626146236
|
||||
v 0.475528258147577 -1.16470831848909e-16 -0.154508497187473
|
||||
v 0.5 -1.22464679914735e-16 7.6571373978539e-16
|
||||
v 0.475528258147577 -1.16470831848909e-16 0.154508497187474
|
||||
v 0.404508497187474 -9.90760072617092e-17 0.293892626146237
|
||||
v 0.293892626146237 -7.19829327805998e-17 0.404508497187473
|
||||
v 0.154508497187475 -3.78436673043417e-17 0.475528258147576
|
||||
v 0.21857645514496 0.136716465258129 0.428407447861946
|
||||
v 0.475945187701446 -0.132880263668928 0.0762824608354488
|
||||
v 0.218576349120797 -0.134908613951094 -0.428980239040003
|
||||
v 0.228603425820446 -0.140038091834834 0.422054269660211
|
||||
v 0.437104447096958 0.151793486569612 0.189468835862535
|
||||
v 0.42898023903994 0.134908613950884 -0.21857634912105
|
||||
v 0.428980239039898 -0.134908613951062 -0.218576349121023
|
||||
v 0.218576349121032 0.134908613951053 -0.428980239039896
|
||||
v 0.340440645253916 0.134908613951044 0.34044064525392
|
||||
v 0.476615030125843 -0.131924241455095 -0.0737163996315581
|
||||
v 0.407622547196207 -0.259520994885 -0.128423955051913
|
||||
v 0.338436818269637 -0.252043139096244 -0.26820659215246
|
||||
v 0.340989631871085 -0.116746524471516 -0.34654915954341
|
||||
v 0.075316277025205 -0.134908613951047 0.475528258147578
|
||||
v 0.0753162770252058 0.134908613951052 -0.475528258147577
|
||||
v 0.337051887252752 0.13152434625125 -0.345104870499591
|
||||
v 0.342307229899869 0.259749321291958 -0.255648294433281
|
||||
v 0.235302886190634 0.257758938760451 0.358040334654413
|
||||
v 0.0930553185121102 0.241091096498632 0.428037137273972
|
||||
v 0.414887348894352 0.253233345682864 -0.117223548665273
|
||||
v 0.309219636002729 0.365205559163796 -0.144941768535501
|
||||
v 0.116382730487621 0.357335962703667 0.329797013029059
|
||||
v 0.220295554503833 0.356044147287606 -0.273317459830304
|
||||
v 0.173924737961772 0.443407381211481 -0.152118637293744
|
||||
v 0.0757439138278267 0.415836842579461 -0.2671003179923
|
||||
v 0.0224933467184133 0.480041055177656 -0.138038526134294
|
||||
v 0.248065266401332 0.358015947011543 0.245536566096914
|
||||
v 0.138163331821839 0.43047956133561 0.21353744639334
|
||||
v 0.360552014587397 0.346405942121308 -0.00227333235984791
|
||||
v 0.123093945281709 0.484207258358844 -0.0197790694319915
|
||||
v -0.0375624502146155 0.498585389330104 0.0012930121510933
|
||||
v -0.0319756224028659 0.329253812136088 0.374925975048146
|
||||
v -0.0571707300985015 0.188277472409031 0.459655415505214
|
||||
v 0.44634465869394 0.222444950782125 0.0359817943817138
|
||||
v 0.114071738612042 0.30750614917439 -0.377395822274126
|
||||
v 0.236387555749274 0.430565411758525 0.0934577427723124
|
||||
v 0.378115930351658 0.292151103254715 0.147227973161872
|
||||
v 0.0698331513994325 -0.131524346251195 -0.477309833660296
|
||||
v -0.0276507157238025 0.368077837732622 -0.337274581446689
|
||||
v -0.132019323454869 0.46789161623721 -0.116826083086996
|
||||
v -0.178527337205295 0.268217150323689 0.382344805303572
|
||||
v -0.195982573985885 0.117715178528912 0.444672876885665
|
||||
v -0.188769871137012 0.462097824846099 0.0288363663352296
|
||||
v -0.311118332326446 0.185953595932789 0.344422187801651
|
||||
v 0.298513275017753 -0.364576673892107 -0.167253321318123
|
||||
v -0.27446477920923 0.408828269442573 -0.0867671082739308
|
||||
v -0.321076581736832 0.0337877006396921 0.381796044958135
|
||||
v -0.406068994209582 0.0890512487956863 0.27780901178606
|
||||
v -0.396337226815336 -0.0658166787739775 0.297632268807486
|
||||
v 0.137344602759695 -0.267387515925555 0.399550217644719
|
||||
v -0.469353412437567 -0.00745235730436951 0.172197086513736
|
||||
v -0.438850244007533 -0.16046355744979 0.17793793880195
|
||||
v -0.488260481987745 -0.0978280168539874 0.0450708425427184
|
||||
v -0.433483128474169 -0.244453321072111 0.0483213321946162
|
||||
v -0.460620100758965 -0.173287974513347 -0.0883198769579221
|
||||
v -0.383511806626786 -0.309356779000242 -0.08495338406711
|
||||
v -0.336717499334961 -0.365993326701377 0.0516740791080927
|
||||
v -0.267862281691792 -0.414575366652434 -0.0798565176542698
|
||||
v -0.205085219904653 -0.452251021719178 0.0583872069088724
|
||||
v -0.389473197418456 -0.226083984285031 -0.217247924138414
|
||||
v -0.445256364809781 -0.0799966822341631 -0.212949055945092
|
||||
v -0.00351125947165275 -0.267035886479874 0.422704987418922
|
||||
v -0.353169743739217 -0.125114465368412 -0.331085340452809
|
||||
v -0.38892388844103 0.0261181792321889 -0.313139026174485
|
||||
v -0.278756909608118 -0.262391732725563 -0.321628922740179
|
||||
v -0.249429844449192 -0.39750217428021 0.172559480007787
|
||||
v -0.125203314206269 -0.478452051724907 -0.0735375027587528
|
||||
v -0.0528582364531956 -0.493487744300911 0.0606288138087549
|
||||
v 0.271731582933658 -0.249600298700644 0.337433901267964
|
||||
v -0.495847117939593 0.0542719818547096 0.034499095880349
|
||||
v 0.341636271151409 -0.364235836672196 -0.0248377438078891
|
||||
v -0.278221380393658 -0.0165162196036634 -0.415114535979952
|
||||
v -0.385894465893779 0.231366911979078 0.218070661102819
|
||||
v 0.129422773211733 -0.26368230955868 -0.404624993543385
|
||||
v 0.17079787798835 -0.360453290963367 0.301498772648173
|
||||
v -0.2972397651044 0.134475553784439 -0.378899521608367
|
||||
v -0.390729424978202 0.17308135749756 -0.259563788196669
|
||||
v 0.0302401087170613 -0.494617483324727 -0.0666264287973931
|
||||
v -0.0447104151313644 -0.455911463185833 -0.200363960118914
|
||||
v -0.289781305004565 -0.107480642258869 0.393032704503674
|
||||
v -0.28072748874216 0.276043192337753 -0.308208100199367
|
||||
v 0.106085899784673 -0.483055958177403 0.0735032185430484
|
||||
v -0.143288452953271 0.380504725979635 0.291006138693707
|
||||
v -0.0207720062787277 -0.262149359393134 -0.425260199319106
|
||||
v -0.0793282266177742 -0.112493174960849 0.480679017691543
|
||||
v -0.210229488803243 0.104747954203238 -0.441397131988602
|
||||
v 0.435024352571936 -0.127806035969131 0.210759174982314
|
||||
v 0.298839864283654 -0.34288662805342 0.207661974894498
|
||||
v -0.343961566185834 -0.213169748618088 0.293681969588004
|
||||
v -0.217656630917657 -0.259665634918282 0.367694641054313
|
||||
v -0.318981501523703 0.381763369474201 0.0500752574969736
|
||||
v -0.395445063483211 0.303503289973959 -0.0388452666581461
|
||||
v 0.00695685172784659 -0.466794760772503 0.179037017204205
|
||||
v -0.141786434074944 -0.0639250457860653 -0.475194902785753
|
||||
v 0.123376202006679 -0.445805073774975 -0.189831896621448
|
||||
v 0.0273264572598231 -0.36207385125428 -0.343737968475292
|
||||
v -0.179178868825853 0.231344360320625 -0.40543152308883
|
||||
v -0.131442519100517 -0.37228536331636 -0.30680037880178
|
||||
v 0.213344976802497 -0.44944368426887 -0.0498427080320272
|
||||
v -0.095411435088729 0.468568967697982 0.146081417588813
|
||||
v 0.19556911033449 -0.349389679263868 -0.299465482329545
|
||||
v -0.212579734450761 0.392914303643436 -0.22456225527287
|
||||
v 0.00442729082563762 0.431790532829453 0.252066131907487
|
||||
v 0.251435921428911 -0.424020659066107 0.0835850351458869
|
||||
v -0.0716881267417996 0.0362403081699758 0.493505271043782
|
||||
v 0.409702957808806 -0.250532734704164 0.139200701163351
|
||||
v 0.354048851093961 -0.123591021755264 0.33071841554491
|
||||
v -0.409329654955812 0.269763307055223 0.0983717019288848
|
||||
v -0.23775056881332 0.409432492346691 0.160747321096556
|
||||
v -0.280167779637764 0.310303261210272 0.274258821799984
|
||||
v 0.0390199999029228 -0.340176969429353 0.364358434892671
|
||||
v -0.106955495739533 -0.389774683020182 0.294340310538035
|
||||
v -0.125152025350624 -0.457070129870627 0.159448634144933
|
||||
v 0.250205349609497 0.430527105380925 -0.0452072401182732
|
||||
v -0.15862733630032 -0.0449406159687499 0.472035707563119
|
||||
v -0.372118237460504 -0.283526014116421 0.176468174662014
|
||||
v -0.235245742246689 -0.152187819676347 -0.41412354231191
|
||||
v 0.479986141812706 0.124680814448665 -0.063780860578784
|
||||
v -0.0761042573074939 0.431963531953512 -0.240032600039915
|
||||
v -0.288453021308633 -0.353652776154199 -0.204265925734934
|
||||
v -0.458840137015611 0.057463941494015 -0.190167358112447
|
||||
v -0.444083105517519 0.194920415588484 -0.121639742603844
|
||||
v -0.178055249060845 -0.43316536366806 -0.175111667230364
|
||||
v -0.491963173165518 -0.0298523928793253 -0.0841490991531884
|
||||
v -0.45636138284715 0.138396610027018 0.150268648023688
|
||||
v -0.345904715972311 0.313415014736247 -0.179223201639723
|
||||
v -0.153169726530236 -0.269052072762942 -0.392619430258638
|
||||
v -0.0419923946510265 0.170189522618945 -0.468265058681734
|
||||
v 0.243612070418092 0.241981955824921 -0.363452737232445
|
||||
v 0.338867576345089 0.252678472264692 0.2670624559087
|
||||
v 0.426863022631355 -0.25994025908482 0.0147993789376581
|
||||
v 0.158342102182598 -0.434609327079221 0.18984865417522
|
||||
v 0.0452931243905481 0.0952764475019849 0.488744239285072
|
||||
v -0.237259629761916 0.0166159415076913 0.439808797744033
|
||||
v 0.247175666187241 -0.238473344419651 -0.363365730423495
|
||||
v 0.0577997827759178 0.48434516267528 0.10985876616872
|
||||
v -0.334770924239934 0.332574086299653 0.165296416795679
|
||||
v -0.153183582101622 0.339412359720881 -0.333667559470828
|
||||
v 0.36785960116632 -0.228792320684729 0.249666553277471
|
||||
v 0.483390586525237 0.102332156736947 0.0765615475049495
|
||||
v 0.139648641361451 0.213951152339616 -0.429794324507027
|
||||
v -0.0358864034291634 0.302032201639968 -0.396848478920397
|
||||
v -0.180786711862885 -0.175443810495746 0.431897712627121
|
||||
v 0.348215026659532 -0.346723777603642 0.0923521372398145
|
||||
v -0.114480413553308 -0.290654614949134 0.390402522688358
|
||||
v -0.272442803422386 -0.321472772094441 0.269128548588341
|
||||
v -0.466114498296331 0.180818120755528 0.00648703972541844
|
||||
v -0.129415184584831 -0.203585571998795 -0.437955048918034
|
||||
v 0.0643376427947934 -0.412575814735467 0.275030661590622
|
||||
v -0.485934856252322 0.0906364933467189 -0.0751820560562512
|
||||
v -2.77555756156289e-16 3.19189119579733e-16 -1.2490009027033e-16
|
||||
v -0.251828742757562 0.0139490906784806 -0.0181338406388946
|
||||
v 0.197996662720562 -0.0791211777945037 0.136432807235424
|
||||
v 0.125255777218953 0.210831018463626 -0.063969097850248
|
||||
v -0.139628236563409 -0.21265335644906 0.00545121255949739
|
||||
v -0.145223690886062 0.189924594351579 0.11159305462841
|
||||
v -0.112897563504534 -0.0373976158431084 -0.223966661594476
|
||||
v 0.225528258147577 -0.0232431701377701 -0.114912387106339
|
||||
v -0.118530098445147 -0.0689806932344922 0.2117841676383
|
||||
v 0.098269738040353 0.147959392484917 0.178021817259433
|
||||
v 0.100852235573853 -0.219450649709681 -0.0387973024559412
|
||||
v -0.100480207820675 0.192284757140571 -0.148991345058649
|
||||
v 0.08807336311451 0.0516996280513727 -0.271061939721184
|
||||
v 0.272113071694785 0.101244013250397 0.0512575837900759
|
||||
v 0.0341720627218518 -0.221571915156144 0.170600381517002
|
||||
v 0.113793744063312 -0.150466918879953 -0.232830800332848
|
||||
v 0.068592399702004 -0.0245878691620408 0.288679790541826
|
||||
v -0.0741210186337665 0.111594614690448 0.278407708187608
|
||||
v -0.0351094203418499 0.30351870487887 -0.00261521319733849
|
||||
v -0.258447343925187 0.0495111872633636 0.167086499211952
|
||||
v -0.271439309774019 -0.125349807194904 0.104052998028547
|
||||
v -0.0485204373172835 -0.250891695571267 -0.169649174254392
|
||||
v -0.245408905954284 -0.137064807392418 -0.132337064396614
|
||||
v -0.247561324014027 0.19563057757812 -0.0400712992459122
|
||||
v -0.245489451032576 0.0855397985783712 -0.187709278356085
|
||||
v 0.27254656245515 -0.16399276001755 -0.00766125806031415
|
||||
v 0.273716986928946 0.149504817170547 -0.136480234333616
|
||||
v 0.0525334922800396 0.245214764318482 -0.222591039627852
|
||||
v -0.025453222260026 0.265072731295802 0.212780231418037
|
||||
v 0.10188342337719 0.303246953287615 0.102540160700209
|
||||
v -0.14157478784597 -0.241776139413833 0.180194715613577
|
||||
v -0.0121617817639016 -0.325829668630181 0.0394634260162139
|
||||
v 0.222619980200421 0.0438990087026778 0.254181668630204
|
||||
v 0.187862004819913 -0.26556009247797 0.101876795667186
|
||||
v 0.342239361396159 -0.0424148965243595 0.0738730045314498
|
||||
v -0.120466338945889 0.114580505991094 -0.297963959751455
|
||||
v 0.15154406307463 -0.163641254596307 0.268108582070898
|
||||
f 166 170 163 182
|
||||
f 165 162 171 180
|
||||
f 167 171 162 180
|
||||
f 4 5 27 169
|
||||
f 163 166 162 170
|
||||
f 4 24 169 177
|
||||
f 167 173 163 185
|
||||
f 162 163 167 173
|
||||
f 158 136 181 185
|
||||
f 162 171 170 178
|
||||
f 162 163 170 181
|
||||
f 162 167 163 181
|
||||
f 4 169 27 174
|
||||
f 170 171 162 179
|
||||
f 162 173 165 174
|
||||
f 170 178 171 179
|
||||
f 158 181 163 185
|
||||
f 162 176 164 178
|
||||
f 162 170 167 181
|
||||
f 162 170 176 178
|
||||
f 162 166 163 184
|
||||
f 167 170 162 179
|
||||
f 129 169 6 196
|
||||
f 162 165 169 174
|
||||
f 73 176 170 178
|
||||
f 119 181 136 185
|
||||
f 4 169 174 177
|
||||
f 72 132 135 163
|
||||
f 27 174 169 188
|
||||
f 158 119 136 185
|
||||
f 64 66 163 182
|
||||
f 167 162 171 179
|
||||
f 66 135 64 163
|
||||
f 7 129 6 196
|
||||
f 162 173 167 180
|
||||
f 95 177 168 183
|
||||
f 162 177 172 183
|
||||
f 4 24 5 169
|
||||
f 27 169 5 188
|
||||
f 162 169 165 175
|
||||
f 162 164 169 175
|
||||
f 129 175 169 196
|
||||
f 168 177 162 183
|
||||
f 132 161 135 163
|
||||
f 119 148 84 167
|
||||
f 162 165 173 180
|
||||
f 164 162 171 175
|
||||
f 165 171 162 175
|
||||
f 158 81 161 163
|
||||
f 30 171 178 179
|
||||
f 64 81 62 163
|
||||
f 169 162 174 177
|
||||
f 66 163 182 184
|
||||
f 169 177 23 187
|
||||
f 162 170 166 176
|
||||
f 54 167 102 185
|
||||
f 68 166 67 182
|
||||
f 162 168 163 173
|
||||
f 164 171 162 178
|
||||
f 161 158 163 185
|
||||
f 65 68 67 182
|
||||
f 166 168 162 183
|
||||
f 129 6 169 188
|
||||
f 162 163 168 184
|
||||
f 165 175 40 191
|
||||
f 129 169 175 188
|
||||
f 119 167 84 181
|
||||
f 62 64 163 182
|
||||
f 18 169 23 187
|
||||
f 67 182 166 184
|
||||
f 162 168 166 184
|
||||
f 168 174 162 177
|
||||
f 164 162 169 172
|
||||
f 167 181 119 185
|
||||
f 126 178 170 179
|
||||
f 72 163 135 184
|
||||
f 72 132 163 186
|
||||
f 54 180 167 185
|
||||
f 62 163 81 181
|
||||
f 162 168 173 174
|
||||
f 66 135 163 184
|
||||
f 165 174 173 189
|
||||
f 38 141 171 191
|
||||
f 140 174 188 189
|
||||
f 161 163 132 186
|
||||
f 24 23 18 169
|
||||
f 62 163 181 182
|
||||
f 65 182 67 184
|
||||
f 166 162 172 183
|
||||
f 140 174 27 188
|
||||
f 162 166 172 176
|
||||
f 4 14 24 177
|
||||
f 23 169 24 177
|
||||
f 169 172 162 177
|
||||
f 163 173 168 186
|
||||
f 60 181 170 182
|
||||
f 119 148 167 185
|
||||
f 57 173 51 180
|
||||
f 72 163 184 186
|
||||
f 41 35 165 180
|
||||
f 41 37 35 180
|
||||
f 141 171 48 175
|
||||
f 56 177 172 187
|
||||
f 135 161 81 163
|
||||
f 95 49 168 177
|
||||
f 102 54 120 167
|
||||
f 34 140 188 189
|
||||
f 176 178 73 198
|
||||
f 162 172 164 176
|
||||
f 141 171 175 194
|
||||
f 60 170 91 182
|
||||
f 130 37 180 189
|
||||
f 56 23 177 187
|
||||
f 22 18 23 187
|
||||
f 121 55 167 179
|
||||
f 6 169 21 196
|
||||
f 60 91 100 182
|
||||
f 12 30 171 178
|
||||
f 65 66 182 184
|
||||
f 91 170 100 182
|
||||
f 164 172 169 187
|
||||
f 116 178 126 179
|
||||
f 125 165 40 191
|
||||
f 69 67 166 184
|
||||
f 96 73 170 178
|
||||
f 113 51 57 173
|
||||
f 57 173 180 185
|
||||
f 136 119 84 181
|
||||
f 84 167 121 181
|
||||
f 83 75 74 186
|
||||
f 134 131 69 183
|
||||
f 167 179 55 181
|
||||
f 130 180 173 189
|
||||
f 145 179 170 181
|
||||
f 48 171 141 191
|
||||
f 48 175 171 191
|
||||
f 102 167 148 185
|
||||
f 64 135 81 163
|
||||
f 30 178 144 179
|
||||
f 57 180 54 185
|
||||
f 121 52 55 179
|
||||
f 40 175 165 188
|
||||
f 60 91 170 181
|
||||
f 130 51 173 180
|
||||
f 76 183 168 184
|
||||
f 74 75 72 184
|
||||
f 140 19 27 174
|
||||
f 165 180 171 191
|
||||
f 49 174 168 177
|
||||
f 83 74 168 186
|
||||
f 84 121 55 181
|
||||
f 69 70 78 166
|
||||
f 120 167 54 180
|
||||
f 121 167 55 181
|
||||
f 148 121 84 167
|
||||
f 74 128 168 184
|
||||
f 131 166 69 183
|
||||
f 156 170 176 192
|
||||
f 74 75 184 186
|
||||
f 67 68 69 166
|
||||
f 65 67 66 184
|
||||
f 117 164 150 196
|
||||
f 96 156 154 170
|
||||
f 98 150 164 196
|
||||
f 145 170 58 181
|
||||
f 161 133 158 185
|
||||
f 24 18 5 169
|
||||
f 78 183 166 193
|
||||
f 34 32 165 188
|
||||
f 98 117 150 196
|
||||
f 41 35 125 165
|
||||
f 35 34 32 165
|
||||
f 73 156 170 176
|
||||
f 74 184 168 186
|
||||
f 72 184 75 186
|
||||
f 133 161 132 186
|
||||
f 119 102 148 185
|
||||
f 150 164 117 195
|
||||
f 34 188 165 189
|
||||
f 57 54 102 185
|
||||
f 148 102 120 167
|
||||
f 170 181 163 182
|
||||
f 12 178 171 194
|
||||
f 6 18 21 169
|
||||
f 5 169 6 188
|
||||
f 136 62 81 181
|
||||
f 171 180 167 190
|
||||
f 58 170 91 181
|
||||
f 78 166 70 193
|
||||
f 2 168 49 174
|
||||
f 34 140 28 188
|
||||
f 40 125 32 165
|
||||
f 38 48 141 191
|
||||
f 169 174 165 188
|
||||
f 40 175 48 191
|
||||
f 113 130 51 173
|
||||
f 66 72 135 184
|
||||
f 169 187 21 196
|
||||
f 131 166 183 184
|
||||
f 74 128 83 168
|
||||
f 18 21 169 187
|
||||
f 7 6 21 196
|
||||
f 64 65 66 182
|
||||
f 69 166 131 184
|
||||
f 56 112 172 177
|
||||
f 76 168 128 184
|
||||
f 166 182 68 192
|
||||
f 159 95 168 183
|
||||
f 34 165 35 189
|
||||
f 96 170 126 178
|
||||
f 172 183 89 193
|
||||
f 150 118 98 164
|
||||
f 172 177 106 183
|
||||
f 168 183 166 184
|
||||
f 111 167 120 180
|
||||
f 17 5 6 188
|
||||
f 30 171 179 190
|
||||
f 130 37 51 180
|
||||
f 40 165 32 188
|
||||
f 100 182 170 192
|
||||
f 112 106 172 177
|
||||
f 74 76 128 184
|
||||
f 170 179 167 181
|
||||
f 32 125 35 165
|
||||
f 41 165 125 191
|
||||
f 113 173 57 185
|
||||
f 2 168 174 197
|
||||
f 18 6 5 169
|
||||
f 167 180 111 190
|
||||
f 126 170 145 179
|
||||
f 12 144 30 178
|
||||
f 91 126 154 170
|
||||
f 69 68 70 166
|
||||
f 4 27 19 174
|
||||
f 137 92 173 186
|
||||
f 25 73 178 198
|
||||
f 29 171 141 194
|
||||
f 60 58 91 181
|
||||
f 120 167 111 190
|
||||
f 111 120 54 180
|
||||
f 150 118 164 198
|
||||
f 30 33 29 171
|
||||
f 69 131 67 184
|
||||
f 95 49 159 168
|
||||
f 68 182 127 192
|
||||
f 117 187 164 196
|
||||
f 166 176 170 192
|
||||
f 33 171 30 190
|
||||
f 57 51 54 180
|
||||
f 137 92 113 173
|
||||
f 22 23 56 187
|
||||
f 37 36 35 189
|
||||
f 29 38 141 171
|
||||
f 150 164 195 198
|
||||
f 180 190 171 191
|
||||
f 145 91 58 170
|
||||
f 41 180 165 191
|
||||
f 82 187 172 195
|
||||
f 137 173 185 186
|
||||
f 113 137 173 185
|
||||
f 112 106 177 183
|
||||
f 164 187 117 195
|
||||
f 154 170 156 192
|
||||
f 148 120 121 167
|
||||
f 165 188 174 189
|
||||
f 76 138 168 183
|
||||
f 116 96 126 178
|
||||
f 76 138 128 168
|
||||
f 82 56 172 187
|
||||
f 172 176 166 193
|
||||
f 9 98 118 164
|
||||
f 30 29 12 171
|
||||
f 70 166 192 193
|
||||
f 33 38 29 171
|
||||
f 165 175 169 188
|
||||
f 96 73 156 170
|
||||
f 141 175 16 194
|
||||
f 96 25 73 178
|
||||
f 45 175 40 188
|
||||
f 98 164 9 196
|
||||
f 121 94 52 190
|
||||
f 106 56 112 172
|
||||
f 70 68 77 166
|
||||
f 70 192 124 193
|
||||
f 169 175 164 196
|
||||
f 31 45 40 188
|
||||
f 172 177 169 187
|
||||
f 106 89 172 183
|
||||
f 113 149 130 173
|
||||
f 149 189 173 197
|
||||
f 121 167 94 190
|
||||
f 171 175 165 191
|
||||
f 93 110 193 195
|
||||
f 172 193 110 195
|
||||
f 125 40 47 191
|
||||
f 3 49 14 177
|
||||
f 96 154 126 170
|
||||
f 78 90 183 193
|
||||
f 152 26 174 189
|
||||
f 113 57 137 185
|
||||
f 16 194 175 196
|
||||
f 60 62 181 182
|
||||
f 110 82 172 195
|
||||
f 92 149 113 173
|
||||
f 146 23 24 177
|
||||
f 34 28 32 188
|
||||
f 163 185 173 186
|
||||
f 72 75 132 186
|
||||
f 91 145 126 170
|
||||
f 38 171 33 191
|
||||
f 124 192 104 193
|
||||
f 18 22 21 187
|
||||
f 77 166 68 192
|
||||
f 130 36 37 189
|
||||
f 30 179 43 190
|
||||
f 131 183 76 184
|
||||
f 89 110 172 193
|
||||
f 121 120 94 167
|
||||
f 9 164 118 194
|
||||
f 173 174 168 197
|
||||
f 12 171 29 194
|
||||
f 56 23 112 177
|
||||
f 116 1 96 178
|
||||
f 17 27 5 188
|
||||
f 140 27 28 188
|
||||
f 104 192 176 193
|
||||
f 120 94 167 190
|
||||
f 112 177 107 183
|
||||
f 82 56 110 172
|
||||
f 169 164 187 196
|
||||
f 164 175 171 194
|
||||
f 118 194 164 198
|
||||
f 3 174 49 177
|
||||
f 9 164 194 196
|
||||
f 70 166 77 192
|
||||
f 167 180 173 185
|
||||
f 146 24 14 177
|
||||
f 30 44 43 179
|
||||
f 101 154 156 192
|
||||
f 152 174 140 189
|
||||
f 166 182 163 184
|
||||
f 92 149 173 197
|
||||
f 171 190 33 191
|
||||
f 60 63 62 182
|
||||
f 45 129 175 188
|
||||
f 163 181 167 185
|
||||
f 150 195 99 198
|
||||
f 167 179 171 190
|
||||
f 143 193 176 195
|
||||
f 164 176 172 195
|
||||
f 171 178 164 194
|
||||
f 164 178 176 198
|
||||
f 9 194 16 196
|
||||
f 129 17 6 188
|
||||
f 78 89 90 193
|
||||
f 10 118 15 194
|
||||
f 10 15 178 194
|
||||
f 150 99 80 198
|
||||
f 83 186 168 197
|
||||
f 111 190 180 191
|
||||
f 77 68 127 192
|
||||
f 127 68 65 182
|
||||
f 118 15 194 198
|
||||
f 10 15 11 178
|
||||
f 19 3 4 174
|
||||
f 9 16 8 196
|
||||
f 45 31 129 188
|
||||
f 30 144 44 179
|
||||
f 149 153 189 197
|
||||
f 40 32 31 188
|
||||
f 159 168 138 183
|
||||
f 124 123 104 192
|
||||
f 89 183 90 193
|
||||
f 104 176 143 193
|
||||
f 62 63 64 182
|
||||
f 137 185 133 186
|
||||
f 178 194 15 198
|
||||
f 47 40 48 191
|
||||
f 89 110 106 172
|
||||
f 75 83 87 186
|
||||
f 123 176 104 192
|
||||
f 105 49 2 168
|
||||
f 107 177 95 183
|
||||
f 87 186 83 197
|
||||
f 173 186 92 197
|
||||
f 73 122 176 198
|
||||
f 159 138 95 183
|
||||
f 149 153 50 189
|
||||
f 112 107 106 183
|
||||
f 137 133 88 186
|
||||
f 120 111 94 190
|
||||
f 110 56 106 172
|
||||
f 93 193 143 195
|
||||
f 170 182 166 192
|
||||
f 173 180 165 189
|
||||
f 10 178 11 194
|
||||
f 114 190 111 191
|
||||
f 52 53 55 179
|
||||
f 173 189 174 197
|
||||
f 139 174 26 189
|
||||
f 19 140 152 174
|
||||
f 116 145 53 179
|
||||
f 36 34 35 189
|
||||
f 100 127 182 192
|
||||
f 116 126 145 179
|
||||
f 134 78 90 183
|
||||
f 112 23 146 177
|
||||
f 89 93 110 193
|
||||
f 115 110 93 195
|
||||
f 63 60 100 182
|
||||
f 159 128 138 168
|
||||
f 11 144 12 178
|
||||
f 46 140 34 189
|
||||
f 168 184 163 186
|
||||
f 16 175 151 196
|
||||
f 106 90 89 183
|
||||
f 76 131 109 183
|
||||
f 41 42 37 180
|
||||
f 2 3 26 174
|
||||
f 143 176 86 195
|
||||
f 70 77 124 192
|
||||
f 137 88 92 186
|
||||
f 16 151 8 196
|
||||
f 73 122 156 176
|
||||
f 3 2 49 174
|
||||
f 150 80 118 198
|
||||
f 155 117 187 195
|
||||
f 160 143 104 176
|
||||
f 84 55 59 181
|
||||
f 25 61 73 198
|
||||
f 33 30 43 190
|
||||
f 166 183 172 193
|
||||
f 105 168 2 197
|
||||
f 107 85 95 177
|
||||
f 150 117 99 195
|
||||
f 79 78 70 193
|
||||
f 141 16 20 194
|
||||
f 16 141 48 175
|
||||
f 111 180 147 191
|
||||
f 45 129 151 175
|
||||
f 86 195 176 198
|
||||
f 156 122 123 176
|
||||
f 122 86 176 198
|
||||
f 11 178 12 194
|
||||
f 29 141 20 194
|
||||
f 92 108 149 197
|
||||
f 156 176 123 192
|
||||
f 82 22 56 187
|
||||
f 160 104 123 176
|
||||
f 95 85 49 177
|
||||
f 48 40 45 175
|
||||
f 84 59 136 181
|
||||
f 51 37 42 180
|
||||
f 105 159 49 168
|
||||
f 13 187 117 196
|
||||
f 43 179 52 190
|
||||
f 139 174 189 197
|
||||
f 134 109 131 183
|
||||
f 160 86 143 176
|
||||
f 96 1 25 178
|
||||
f 114 111 147 191
|
||||
f 59 55 58 181
|
||||
f 19 26 3 174
|
||||
f 99 195 86 198
|
||||
f 110 115 82 195
|
||||
f 155 187 82 195
|
||||
f 60 62 59 181
|
||||
f 71 74 72 184
|
||||
f 25 178 15 198
|
||||
f 158 103 119 185
|
||||
f 152 140 46 189
|
||||
f 175 194 164 196
|
||||
f 43 44 52 179
|
||||
f 164 172 187 195
|
||||
f 59 62 136 181
|
||||
f 100 157 127 192
|
||||
f 93 104 143 193
|
||||
f 15 25 11 178
|
||||
f 59 58 60 181
|
||||
f 73 61 122 198
|
||||
f 99 86 80 198
|
||||
f 54 51 42 180
|
||||
f 102 119 103 185
|
||||
f 67 71 66 184
|
||||
f 71 72 66 184
|
||||
f 39 33 190 191
|
||||
f 64 63 65 182
|
||||
f 152 139 26 189
|
||||
f 160 123 122 176
|
||||
f 39 38 33 191
|
||||
f 132 88 133 186
|
||||
f 21 187 13 196
|
||||
f 92 186 87 197
|
||||
f 124 79 70 193
|
||||
f 2 26 139 174
|
||||
f 76 109 138 183
|
||||
f 114 39 33 190
|
||||
f 38 47 48 191
|
||||
f 117 13 142 187
|
||||
f 142 155 117 187
|
||||
f 153 152 46 189
|
||||
f 25 1 11 178
|
||||
f 41 147 42 180
|
||||
f 42 111 54 180
|
||||
f 98 13 117 196
|
||||
f 122 61 86 198
|
||||
f 105 83 128 168
|
||||
f 176 192 166 193
|
||||
f 107 112 85 177
|
||||
f 122 86 160 176
|
||||
f 41 147 180 191
|
||||
f 76 74 71 184
|
||||
f 13 21 142 187
|
||||
f 2 174 139 197
|
||||
f 131 71 67 184
|
||||
f 85 146 14 177
|
||||
f 142 82 155 187
|
||||
f 36 130 50 189
|
||||
f 97 87 83 197
|
||||
f 87 92 88 186
|
||||
f 41 125 47 191
|
||||
f 42 147 111 180
|
||||
f 83 168 105 197
|
||||
f 155 99 117 195
|
||||
f 155 82 115 195
|
||||
f 45 151 16 175
|
||||
f 57 102 103 185
|
||||
f 49 85 14 177
|
||||
f 158 133 103 185
|
||||
f 39 190 114 191
|
||||
f 44 144 116 179
|
||||
f 115 93 143 195
|
||||
f 8 98 9 196
|
||||
f 1 144 11 178
|
||||
f 63 100 127 182
|
||||
f 168 186 173 197
|
||||
f 146 85 112 177
|
||||
f 139 189 153 197
|
||||
f 108 153 149 197
|
||||
f 52 44 53 179
|
||||
f 32 28 31 188
|
||||
f 44 116 53 179
|
||||
f 108 92 87 197
|
||||
f 21 22 142 187
|
||||
f 176 195 164 198
|
||||
f 90 106 107 183
|
||||
f 10 11 12 194
|
||||
f 138 107 95 183
|
||||
f 82 142 22 187
|
||||
f 28 27 17 188
|
||||
f 7 21 13 196
|
||||
f 131 76 71 184
|
||||
f 100 101 157 192
|
||||
f 176 193 172 195
|
||||
f 20 16 9 194
|
||||
f 152 26 19 174
|
||||
f 88 132 75 186
|
||||
f 164 194 178 198
|
||||
f 129 31 17 188
|
||||
f 57 103 137 185
|
||||
f 127 65 63 182
|
||||
f 159 105 128 168
|
||||
f 139 152 153 189
|
||||
f 138 109 107 183
|
||||
f 137 103 133 185
|
||||
f 79 89 78 193
|
||||
f 94 43 52 190
|
||||
f 16 48 45 175
|
||||
f 25 15 61 198
|
||||
f 36 46 34 189
|
||||
f 12 29 20 194
|
||||
f 75 87 88 186
|
||||
f 77 127 157 192
|
||||
f 9 118 10 194
|
||||
f 111 114 94 190
|
||||
f 97 83 105 197
|
||||
f 99 143 86 195
|
||||
f 80 15 118 198
|
||||
f 8 151 7 196
|
||||
f 124 104 79 193
|
||||
f 134 90 109 183
|
||||
f 39 114 147 191
|
||||
f 33 43 114 190
|
||||
f 79 93 89 193
|
||||
f 77 123 124 192
|
||||
f 36 50 46 189
|
||||
f 79 104 93 193
|
||||
f 31 28 17 188
|
||||
f 97 105 139 197
|
||||
f 61 80 86 198
|
||||
f 139 105 2 197
|
||||
f 109 90 107 183
|
||||
f 8 7 13 196
|
||||
f 143 99 115 195
|
||||
f 98 8 13 196
|
||||
f 47 38 39 191
|
||||
f 41 47 147 191
|
||||
f 153 46 50 189
|
||||
f 157 101 123 192
|
||||
f 94 114 43 190
|
||||
f 115 99 155 195
|
||||
f 157 123 77 192
|
||||
f 12 20 10 194
|
||||
f 156 123 101 192
|
||||
f 61 15 80 198
|
||||
f 20 9 10 194
|
||||
f 47 39 147 191
|
||||
f 97 108 87 197
|
||||
f 139 153 108 197
|
||||
f 139 108 97 197
|
||||
f 181 158 81 136
|
||||
f 181 81 158 163
|
||||
f 69 183 78 134
|
||||
f 78 183 69 166
|
||||
f 185 161 186 163
|
||||
f 185 186 161 133
|
||||
f 180 35 189 37
|
||||
f 180 189 35 165
|
||||
f 179 121 190 167
|
||||
f 179 190 121 52
|
||||
f 177 3 4 14
|
||||
f 177 4 3 174
|
||||
f 55 181 53 58
|
||||
f 55 53 181 179
|
||||
f 145 53 181 58
|
||||
f 145 181 53 179
|
||||
f 100 192 91 101
|
||||
f 100 91 192 170
|
||||
f 154 91 192 101
|
||||
f 154 192 91 170
|
||||
f 196 129 151 7
|
||||
f 196 151 129 175
|
||||
f 189 149 130 50
|
||||
f 189 130 149 173
|
||||
f 116 178 144 1
|
||||
f 116 144 178 179
|
278
cs457-gc/assignment_2_3/data/beam.obj
Normal file
@@ -0,0 +1,278 @@
|
||||
v 0 1 0
|
||||
v 1 1 0
|
||||
v 2 1 0
|
||||
v 3 1 0
|
||||
v 4 1 0
|
||||
v 5 1 0
|
||||
v 6 1 0
|
||||
v 7 1 0
|
||||
v 8 1 0
|
||||
v 9 1 0
|
||||
v 10 1 0
|
||||
v 0 0 0
|
||||
v 1 0 0
|
||||
v 2 0 0
|
||||
v 3 0 0
|
||||
v 4 0 0
|
||||
v 5 0 0
|
||||
v 6 0 0
|
||||
v 7 0 0
|
||||
v 8 0 0
|
||||
v 9 0 0
|
||||
v 10 0 0
|
||||
v 0 1 2
|
||||
v 1 1 2
|
||||
v 2 1 2
|
||||
v 3 1 2
|
||||
v 4 1 2
|
||||
v 5 1 2
|
||||
v 6 1 2
|
||||
v 7 1 2
|
||||
v 8 1 2
|
||||
v 9 1 2
|
||||
v 10 1 2
|
||||
v 0 2 2
|
||||
v 1 2 2
|
||||
v 2 2 2
|
||||
v 3 2 2
|
||||
v 4 2 2
|
||||
v 5 2 2
|
||||
v 6 2 2
|
||||
v 7 2 2
|
||||
v 8 2 2
|
||||
v 9 2 2
|
||||
v 10 2 2
|
||||
v 1 0 1
|
||||
v 2 0 1
|
||||
v 3 0 1
|
||||
v 4 0 1
|
||||
v 5 0 1
|
||||
v 6 0 1
|
||||
v 7 0 1
|
||||
v 8 0 1
|
||||
v 9 0 1
|
||||
v 10 0 1
|
||||
v 0 0 2
|
||||
v 1 0 2
|
||||
v 2 0 2
|
||||
v 3 0 2
|
||||
v 4 0 2
|
||||
v 5 0 2
|
||||
v 6 0 2
|
||||
v 7 0 2
|
||||
v 8 0 2
|
||||
v 9 0 2
|
||||
v 10 0 2
|
||||
v 10 1 1
|
||||
v 10 2 0
|
||||
v 9 2 0
|
||||
v 8 2 0
|
||||
v 7 2 0
|
||||
v 6 2 0
|
||||
v 5 2 0
|
||||
v 4 2 0
|
||||
v 3 2 0
|
||||
v 2 2 0
|
||||
v 1 2 0
|
||||
v 0 2 0
|
||||
v 10 2 1
|
||||
v 9 2 1
|
||||
v 8 2 1
|
||||
v 7 2 1
|
||||
v 6 2 1
|
||||
v 5 2 1
|
||||
v 4 2 1
|
||||
v 3 2 1
|
||||
v 2 2 1
|
||||
v 1 2 1
|
||||
v 0 2 1
|
||||
v 0 1 1
|
||||
v 0 0 1
|
||||
f 36 86 25 24
|
||||
f 1 87 88 89
|
||||
f 12 13 1 45
|
||||
f 85 38 37 26
|
||||
f 87 35 23 24
|
||||
f 48 85 4 47
|
||||
f 61 28 49 60
|
||||
f 46 14 2 3
|
||||
f 9 31 8 52
|
||||
f 85 37 25 26
|
||||
f 19 7 18 51
|
||||
f 61 28 50 49
|
||||
f 49 28 27 60
|
||||
f 85 5 4 73
|
||||
f 3 85 4 74
|
||||
f 28 61 50 29
|
||||
f 32 31 43 79
|
||||
f 23 45 90 89
|
||||
f 28 39 40 82
|
||||
f 10 54 53 21
|
||||
f 48 85 47 26
|
||||
f 48 85 5 4
|
||||
f 7 50 18 51
|
||||
f 50 28 29 6
|
||||
f 85 4 74 73
|
||||
f 88 87 23 89
|
||||
f 77 1 76 87
|
||||
f 13 46 14 2
|
||||
f 1 12 45 90
|
||||
f 87 35 34 23
|
||||
f 1 2 87 89
|
||||
f 9 53 20 21
|
||||
f 29 28 82 6
|
||||
f 29 82 7 6
|
||||
f 48 49 16 5
|
||||
f 25 47 58 46
|
||||
f 15 48 16 4
|
||||
f 16 48 5 4
|
||||
f 2 1 45 89
|
||||
f 1 2 76 87
|
||||
f 8 30 7 51
|
||||
f 35 86 36 24
|
||||
f 45 1 90 89
|
||||
f 76 2 86 87
|
||||
f 80 30 41 81
|
||||
f 85 5 73 84
|
||||
f 30 62 29 51
|
||||
f 50 29 7 6
|
||||
f 23 24 45 89
|
||||
f 77 1 87 88
|
||||
f 76 2 75 86
|
||||
f 48 85 26 27
|
||||
f 2 86 87 24
|
||||
f 3 74 75 86
|
||||
f 3 85 74 86
|
||||
f 3 24 86 2
|
||||
f 2 3 75 86
|
||||
f 23 87 24 89
|
||||
f 30 80 41 42
|
||||
f 28 5 27 83
|
||||
f 30 29 41 81
|
||||
f 47 58 59 26
|
||||
f 15 48 4 47
|
||||
f 88 87 34 23
|
||||
f 87 86 35 24
|
||||
f 13 2 1 45
|
||||
f 55 23 45 90
|
||||
f 86 85 36 25
|
||||
f 13 46 2 45
|
||||
f 46 25 24 57
|
||||
f 5 73 84 72
|
||||
f 36 85 37 25
|
||||
f 3 85 86 25
|
||||
f 25 3 24 86
|
||||
f 85 84 38 27
|
||||
f 10 11 66 54
|
||||
f 59 48 26 27
|
||||
f 48 47 59 26
|
||||
f 46 25 57 58
|
||||
f 23 56 55 45
|
||||
f 85 48 5 27
|
||||
f 85 38 26 27
|
||||
f 23 24 56 45
|
||||
f 46 24 2 45
|
||||
f 3 25 24 46
|
||||
f 3 24 2 46
|
||||
f 24 46 57 45
|
||||
f 24 57 56 45
|
||||
f 87 2 24 89
|
||||
f 24 2 45 89
|
||||
f 47 25 3 46
|
||||
f 3 15 4 47
|
||||
f 10 11 54 22
|
||||
f 14 15 3 47
|
||||
f 46 14 3 47
|
||||
f 49 28 5 27
|
||||
f 48 49 5 27
|
||||
f 47 25 58 26
|
||||
f 85 5 84 27
|
||||
f 47 85 3 26
|
||||
f 9 80 31 79
|
||||
f 47 25 26 3
|
||||
f 3 85 25 26
|
||||
f 85 47 3 4
|
||||
f 48 49 27 60
|
||||
f 59 48 27 60
|
||||
f 31 9 53 52
|
||||
f 50 61 62 29
|
||||
f 33 32 78 66
|
||||
f 31 80 30 42
|
||||
f 40 29 82 81
|
||||
f 63 62 30 51
|
||||
f 30 63 51 52
|
||||
f 41 29 40 81
|
||||
f 33 32 66 54
|
||||
f 9 80 68 69
|
||||
f 82 71 70 7
|
||||
f 5 84 83 72
|
||||
f 32 43 78 79
|
||||
f 29 28 40 82
|
||||
f 5 84 27 83
|
||||
f 33 32 44 78
|
||||
f 9 80 79 68
|
||||
f 8 7 19 51
|
||||
f 28 27 39 83
|
||||
f 28 39 82 83
|
||||
f 28 50 49 6
|
||||
f 65 64 32 53
|
||||
f 82 71 7 6
|
||||
f 29 82 81 7
|
||||
f 81 70 8 7
|
||||
f 84 38 27 83
|
||||
f 27 38 39 83
|
||||
f 32 43 44 78
|
||||
f 9 31 32 79
|
||||
f 31 80 42 79
|
||||
f 31 42 43 79
|
||||
f 67 78 10 11
|
||||
f 32 9 10 53
|
||||
f 62 50 29 51
|
||||
f 71 82 83 6
|
||||
f 49 16 5 17
|
||||
f 81 82 70 7
|
||||
f 50 49 6 17
|
||||
f 79 68 67 10
|
||||
f 79 9 68 10
|
||||
f 50 6 18 17
|
||||
f 78 10 11 66
|
||||
f 78 79 67 10
|
||||
f 32 9 79 10
|
||||
f 78 32 79 66
|
||||
f 79 32 10 66
|
||||
f 78 79 10 66
|
||||
f 9 10 53 21
|
||||
f 82 28 83 6
|
||||
f 71 83 72 6
|
||||
f 69 81 70 8
|
||||
f 64 31 53 52
|
||||
f 28 5 83 6
|
||||
f 83 5 72 6
|
||||
f 80 30 81 8
|
||||
f 28 49 5 6
|
||||
f 64 63 31 52
|
||||
f 80 81 69 8
|
||||
f 9 80 69 8
|
||||
f 7 50 6 18
|
||||
f 80 9 31 8
|
||||
f 80 31 30 8
|
||||
f 31 63 30 52
|
||||
f 31 30 8 52
|
||||
f 30 81 8 7
|
||||
f 30 29 81 7
|
||||
f 19 8 51 52
|
||||
f 33 65 32 54
|
||||
f 49 5 6 17
|
||||
f 10 54 21 22
|
||||
f 29 50 7 51
|
||||
f 30 29 7 51
|
||||
f 65 32 54 53
|
||||
f 9 53 52 20
|
||||
f 31 9 32 53
|
||||
f 64 31 32 53
|
||||
f 32 10 66 53
|
||||
f 66 10 54 53
|
||||
f 32 66 54 53
|
||||
f 8 30 51 52
|
||||
f 8 9 52 20
|
||||
f 19 8 52 20
|
1526
cs457-gc/assignment_2_3/data/dinosaur.obj
Normal file
@@ -0,0 +1,413 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Description\n",
|
||||
"\n",
|
||||
"This notebook intends to gather all the functionalities you'll have to implement for assignment 2.3.\n",
|
||||
"\n",
|
||||
"# Load libraries"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import igl\n",
|
||||
"import meshplot as mp\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"import sys as _sys\n",
|
||||
"_sys.path.append(\"../src\")\n",
|
||||
"from elasticsolid import *\n",
|
||||
"from elasticenergy import *\n",
|
||||
"from matplotlib import gridspec\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"shadingOptions = {\n",
|
||||
" \"flat\":True,\n",
|
||||
" \"wireframe\":False, \n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"rot = np.array(\n",
|
||||
" [[1, 0, 0 ],\n",
|
||||
" [0, 0, 1],\n",
|
||||
" [0, -1, 0 ]]\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Load mesh\n",
|
||||
"\n",
|
||||
"Several meshes are available for you to play with under `data/`: `ball.obj`, `dinosaur.obj`, and `beam.obj`. You can also uncomment the few commented lines below to manipulate a simple mesh made out of 2 tetrahedra."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "cde9c07200964ca49ba30dc0805f86b4",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-1.987469…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"v, _, _, t, _, _ = igl.read_obj(\"../data/dinosaur.obj\")\n",
|
||||
"# v, _, _, t, _, _ = igl.read_obj(\"../data/beam.obj\")\n",
|
||||
"\n",
|
||||
"# t = np.array([\n",
|
||||
"# [0, 1, 2, 3],\n",
|
||||
"# [1, 2, 3, 4]\n",
|
||||
"# ])\n",
|
||||
"# v = np.array([\n",
|
||||
"# [0., 0., 0.],\n",
|
||||
"# [1., 0., 0.],\n",
|
||||
"# [0., 1., 0.],\n",
|
||||
"# [0., 0., 1.],\n",
|
||||
"# [2/3, 2/3, 2/3]\n",
|
||||
"# ])\n",
|
||||
"\n",
|
||||
"be = igl.edges(igl.boundary_facets(t))\n",
|
||||
"e = igl.edges(t)\n",
|
||||
"\n",
|
||||
"aabb = np.max(v, axis=0) - np.min(v, axis=0)\n",
|
||||
"length_scale = np.mean(aabb)\n",
|
||||
"\n",
|
||||
"p = mp.plot(v @ rot.T, t, shading=shadingOptions)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Linear/Non-Linear Elastic Solid\n",
|
||||
"\n",
|
||||
"## Instantiation\n",
|
||||
"\n",
|
||||
"We first specify the elasticity model to use for the elastic solid, as well as pinned vertices, and volumetric forces."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rho = 131 # [kg.m-3]\n",
|
||||
"young = 3e8 # [Pa] \n",
|
||||
"poisson = 0.2\n",
|
||||
"force_mass = np.zeros(shape = (3,))\n",
|
||||
"force_mass[2] = - rho * 9.81\n",
|
||||
"\n",
|
||||
"# minX = np.min(v[:, 0])\n",
|
||||
"# pin_idx = np.arange(v.shape[0])[v[:, 0] < minX + 0.2*aabb[0]]\n",
|
||||
"minZ = np.min(v[:, 2])\n",
|
||||
"pin_idx = np.arange(v.shape[0])[v[:, 2] < minZ + 0.1*aabb[2]]\n",
|
||||
"\n",
|
||||
"# ee = LinearElasticEnergy(young, poisson)\n",
|
||||
"ee = NeoHookeanElasticEnergy(young, poisson)\n",
|
||||
"solid = ElasticSolid(v, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Deform the mesh\n",
|
||||
"\n",
|
||||
"This should now involve elastic forces computation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "7fabee312a0d47a08145c7eca8b09306",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-3.974938…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"3"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"v_def = v.copy()\n",
|
||||
"v_def[:, 0] *= 2.\n",
|
||||
"solid.update_def_shape(v_def)\n",
|
||||
"\n",
|
||||
"p = mp.plot(solid.v_def @ rot.T, solid.t, shading=shadingOptions)\n",
|
||||
"p.add_points(solid.v_def[solid.pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.1 * length_scale})\n",
|
||||
"forcesScale = 2 * np.max(np.linalg.norm(solid.f_ext, axis=1))\n",
|
||||
"p.add_lines(solid.v_def @ rot.T, (solid.v_def + solid.f_ext / forcesScale) @ rot.T)\n",
|
||||
"p.add_edges(v @ rot.T, be, shading={\"line_color\": \"blue\"})\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Find equilibrium\n",
|
||||
"\n",
|
||||
"We compare different methods: number of steps, computation time."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"n_steps = 1000\n",
|
||||
"thresh = 1.\n",
|
||||
"v_init = v.copy()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Gradient descent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/opt/notebooks/assignment_2_3/notebook/../src/elasticenergy.py:133: RuntimeWarning: invalid value encountered in log\n",
|
||||
" j = np.log(np.linalg.det(jac))\n",
|
||||
"/opt/notebooks/assignment_2_3/notebook/../src/elasticenergy.py:148: RuntimeWarning: invalid value encountered in log\n",
|
||||
" self.logJ = np.log(np.linalg.det(jac))\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run ../src/Utils.py\n",
|
||||
"\n",
|
||||
"report_GD = equilibrium_convergence_report_GD(solid, v_init, n_steps, 1e-8, thresh=thresh)\n",
|
||||
"energies_el_GD = report_GD['energies_el']\n",
|
||||
"energies_ext_GD = report_GD['energies_ext']\n",
|
||||
"energy_GD = energies_el_GD + energies_ext_GD\n",
|
||||
"residuals_GD = report_GD['residuals']\n",
|
||||
"times_GD = report_GD['times']\n",
|
||||
"idx_stop_GD = report_GD['idx_stop']\n",
|
||||
"v_def_GD = solid.v_def.copy()\n",
|
||||
"\n",
|
||||
"# Lastly, plot the resulting shape\n",
|
||||
"p = mp.plot(v_def_GD @ rot.T, solid.t, shading=shadingOptions)\n",
|
||||
"forcesScale = 2 * np.max(np.linalg.norm(solid.f_ext, axis=1))\n",
|
||||
"p.add_lines(v_def_GD @ rot.T, (solid.v_def + solid.f_ext / forcesScale) @ rot.T)\n",
|
||||
"p.add_points(v_def_GD[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.1 * length_scale})\n",
|
||||
"p.add_edges(v @ rot.T, be, shading={\"line_color\": \"blue\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## BFGS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"report_BFGS = equilibrium_convergence_report_BFGS(solid, v_init, n_steps, 1e-8, thresh=thresh)\n",
|
||||
"energies_el_BFGS = report_BFGS['energies_el']\n",
|
||||
"energies_ext_BFGS = report_BFGS['energies_ext']\n",
|
||||
"energy_BFGS = energies_el_BFGS + energies_ext_BFGS\n",
|
||||
"residuals_BFGS = report_BFGS['residuals']\n",
|
||||
"times_BFGS = report_BFGS['times']\n",
|
||||
"idx_stop_BFGS = report_BFGS['idx_stop']\n",
|
||||
"v_def_BFGS = solid.v_def.copy()\n",
|
||||
"\n",
|
||||
"# Lastly, plot the resulting shape\n",
|
||||
"p = mp.plot(v_def_BFGS @ rot.T, solid.t, shading=shadingOptions)\n",
|
||||
"forcesScale = 2 * np.max(np.linalg.norm(solid.f_ext, axis=1))\n",
|
||||
"p.add_lines(v_def_BFGS @ rot.T, (solid.v_def + solid.f_ext / forcesScale) @ rot.T)\n",
|
||||
"p.add_points(v_def_BFGS[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.1 * length_scale})\n",
|
||||
"p.add_edges(v @ rot.T, be, shading={\"line_color\": \"blue\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Newton-CG"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"report_NCG = equilibrium_convergence_report_NCG(solid, v_init, n_steps, thresh=thresh)\n",
|
||||
"energies_el_NCG = report_NCG['energies_el']\n",
|
||||
"energies_ext_NCG = report_NCG['energies_ext']\n",
|
||||
"energy_NCG = energies_el_NCG + energies_ext_NCG\n",
|
||||
"residuals_NCG = report_NCG['residuals']\n",
|
||||
"times_NCG = report_NCG['times']\n",
|
||||
"idx_stop_NCG = report_NCG['idx_stop']\n",
|
||||
"v_def_NCG = solid.v_def.copy()\n",
|
||||
"\n",
|
||||
"# Lastly, plot the resulting shape\n",
|
||||
"p = mp.plot(v_def_NCG @ rot.T, solid.t, shading=shadingOptions)\n",
|
||||
"forcesScale = 2 * np.max(np.linalg.norm(solid.f_ext, axis=1))\n",
|
||||
"p.add_lines(v_def_NCG @ rot.T, (solid.v_def + solid.f_ext / forcesScale) @ rot.T)\n",
|
||||
"p.add_points(v_def_NCG[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.1 * length_scale})\n",
|
||||
"p.add_edges(v @ rot.T, be, shading={\"line_color\": \"blue\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Compare the different algorithms"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cmap = plt.get_cmap('viridis')\n",
|
||||
"colors = cmap(np.linspace(0., 1., 4))\n",
|
||||
"\n",
|
||||
"gs = gridspec.GridSpec(nrows=1, ncols=1, width_ratios=[1], height_ratios=[1])\n",
|
||||
"fig = plt.figure(figsize=(10, 6))\n",
|
||||
"\n",
|
||||
"axTmp = plt.subplot(gs[0, 0])\n",
|
||||
"axTmp.plot(times_GD[:idx_stop_GD+1], residuals_GD[:idx_stop_GD+1], c=colors[0], \n",
|
||||
" label=\"Gradient Descent ({:}its)\".format(idx_stop_GD))\n",
|
||||
"axTmp.plot(times_BFGS[:idx_stop_BFGS+1], residuals_BFGS[:idx_stop_BFGS+1], c=colors[1], \n",
|
||||
" label=\"BFGS ({:}its)\".format(idx_stop_BFGS))\n",
|
||||
"axTmp.plot(times_NCG[:idx_stop_NCG+1], residuals_NCG[:idx_stop_NCG+1], c=colors[2], \n",
|
||||
" label=\"Newton-CG ({:}its)\".format(idx_stop_NCG))\n",
|
||||
"y_lim = axTmp.get_ylim()\n",
|
||||
"axTmp.set_title(\"Residuals as optimization goes\", fontsize=14)\n",
|
||||
"axTmp.set_xlabel(\"Computation time [s]\", fontsize=12)\n",
|
||||
"axTmp.set_ylabel(\"Force residuals [N]\", fontsize=12)\n",
|
||||
"axTmp.set_ylim(y_lim)\n",
|
||||
"plt.legend(fontsize=12)\n",
|
||||
"plt.grid()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"gs = gridspec.GridSpec(nrows=1, ncols=1, width_ratios=[1], height_ratios=[1])\n",
|
||||
"fig = plt.figure(figsize=(10, 6))\n",
|
||||
"\n",
|
||||
"axTmp = plt.subplot(gs[0, 0])\n",
|
||||
"axTmp.plot(times_GD[:idx_stop_GD+1], energy_GD[:idx_stop_GD+1], c=colors[0], \n",
|
||||
" label=\"Gradient Descent ({:}its)\".format(idx_stop_GD))\n",
|
||||
"axTmp.plot(times_BFGS[:idx_stop_BFGS+1], energy_BFGS[:idx_stop_BFGS+1], c=colors[1], \n",
|
||||
" label=\"BFGS ({:}its)\".format(idx_stop_BFGS))\n",
|
||||
"axTmp.plot(times_NCG[:idx_stop_NCG+1], energy_NCG[:idx_stop_NCG+1], c=colors[2], \n",
|
||||
" label=\"Newton-CG ({:}its)\".format(idx_stop_NCG))\n",
|
||||
"y_lim = axTmp.get_ylim()\n",
|
||||
"axTmp.set_title(\"Total energy as optimization goes\", fontsize=14)\n",
|
||||
"axTmp.set_xlabel(\"Computation time [s]\", fontsize=12)\n",
|
||||
"axTmp.set_ylabel(\"Energy [J]\", fontsize=12)\n",
|
||||
"axTmp.set_ylim(y_lim)\n",
|
||||
"plt.legend(fontsize=12)\n",
|
||||
"plt.grid()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"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"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
467
cs457-gc/assignment_2_3/notebook/hw_2.3.ipynb
Normal file
@@ -0,0 +1,467 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Description\n",
|
||||
"\n",
|
||||
"This notebook intends to gather all the functionalities you'll have to implement for assignment 2.3.\n",
|
||||
"\n",
|
||||
"# Load libraries"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import igl\n",
|
||||
"import meshplot as mp\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"import sys as _sys\n",
|
||||
"_sys.path.append(\"../src\")\n",
|
||||
"from elasticsolid import *\n",
|
||||
"from elasticenergy import *\n",
|
||||
"from matplotlib import gridspec\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"shadingOptions = {\n",
|
||||
" \"flat\":True,\n",
|
||||
" \"wireframe\":False, \n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"rot = np.array(\n",
|
||||
" [[1, 0, 0 ],\n",
|
||||
" [0, 0, 1],\n",
|
||||
" [0, -1, 0 ]]\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Load mesh\n",
|
||||
"\n",
|
||||
"Several meshes are available for you to play with under `data/`: `ball.obj`, `dinosaur.obj`, and `beam.obj`. You can also uncomment the few commented lines below to manipulate a simple mesh made out of 2 tetrahedra."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "bc63cdd8cfe14603b4e54d871b4206d7",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-1.987469…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"v, _, _, t, _, _ = igl.read_obj(\"../data/dinosaur.obj\")\n",
|
||||
"# v, _, _, t, _, _ = igl.read_obj(\"../data/beam.obj\")\n",
|
||||
"\n",
|
||||
"# t = np.array([\n",
|
||||
"# [0, 1, 2, 3],\n",
|
||||
"# [1, 2, 3, 4]\n",
|
||||
"# ])\n",
|
||||
"# v = np.array([\n",
|
||||
"# [0., 0., 0.],\n",
|
||||
"# [1., 0., 0.],\n",
|
||||
"# [0., 1., 0.],\n",
|
||||
"# [0., 0., 1.],\n",
|
||||
"# [2/3, 2/3, 2/3]\n",
|
||||
"# ])\n",
|
||||
"\n",
|
||||
"be = igl.edges(igl.boundary_facets(t))\n",
|
||||
"e = igl.edges(t)\n",
|
||||
"\n",
|
||||
"aabb = np.max(v, axis=0) - np.min(v, axis=0)\n",
|
||||
"length_scale = np.mean(aabb)\n",
|
||||
"\n",
|
||||
"p = mp.plot(v @ rot.T, t, shading=shadingOptions)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Linear/Non-Linear Elastic Solid\n",
|
||||
"\n",
|
||||
"## Instantiation\n",
|
||||
"\n",
|
||||
"We first specify the elasticity model to use for the elastic solid, as well as pinned vertices, and volumetric forces."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rho = 131 # [kg.m-3]\n",
|
||||
"young = 3e8 # [Pa] \n",
|
||||
"poisson = 0.2\n",
|
||||
"force_mass = np.zeros(shape = (3,))\n",
|
||||
"force_mass[2] = - rho * 9.81\n",
|
||||
"\n",
|
||||
"# minX = np.min(v[:, 0])\n",
|
||||
"# pin_idx = np.arange(v.shape[0])[v[:, 0] < minX + 0.2*aabb[0]]\n",
|
||||
"minZ = np.min(v[:, 2])\n",
|
||||
"pin_idx = np.arange(v.shape[0])[v[:, 2] < minZ + 0.1*aabb[2]]\n",
|
||||
"\n",
|
||||
"# ee = LinearElasticEnergy(young, poisson)\n",
|
||||
"ee = NeoHookeanElasticEnergy(young, poisson)\n",
|
||||
"solid = ElasticSolid(v, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Deform the mesh\n",
|
||||
"\n",
|
||||
"This should now involve elastic forces computation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "b6c6920e14be4332b4a96e814c9236da",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-3.974938…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"3"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"v_def = v.copy()\n",
|
||||
"v_def[:, 0] *= 2.\n",
|
||||
"solid.update_def_shape(v_def)\n",
|
||||
"\n",
|
||||
"p = mp.plot(solid.v_def @ rot.T, solid.t, shading=shadingOptions)\n",
|
||||
"p.add_points(solid.v_def[solid.pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.1 * length_scale})\n",
|
||||
"forcesScale = 2 * np.max(np.linalg.norm(solid.f_ext, axis=1))\n",
|
||||
"p.add_lines(solid.v_def @ rot.T, (solid.v_def + solid.f_ext / forcesScale) @ rot.T)\n",
|
||||
"p.add_edges(v @ rot.T, be, shading={\"line_color\": \"blue\"})\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Find equilibrium\n",
|
||||
"\n",
|
||||
"We compare different methods: number of steps, computation time."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"n_steps = 1000\n",
|
||||
"thresh = 1.\n",
|
||||
"v_init = v.copy()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Gradient descent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "fe18307f9c24439db1ed8fc58928c284",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-1.987469…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"3"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run ../src/Utils.py\n",
|
||||
"\n",
|
||||
"report_GD = equilibrium_convergence_report_GD(solid, v_init, n_steps, 1e-8, thresh=thresh)\n",
|
||||
"energies_el_GD = report_GD['energies_el']\n",
|
||||
"energies_ext_GD = report_GD['energies_ext']\n",
|
||||
"energy_GD = energies_el_GD + energies_ext_GD\n",
|
||||
"residuals_GD = report_GD['residuals']\n",
|
||||
"times_GD = report_GD['times']\n",
|
||||
"idx_stop_GD = report_GD['idx_stop']\n",
|
||||
"v_def_GD = solid.v_def.copy()\n",
|
||||
"\n",
|
||||
"# Lastly, plot the resulting shape\n",
|
||||
"p = mp.plot(v_def_GD @ rot.T, solid.t, shading=shadingOptions)\n",
|
||||
"forcesScale = 2 * np.max(np.linalg.norm(solid.f_ext, axis=1))\n",
|
||||
"p.add_lines(v_def_GD @ rot.T, (solid.v_def + solid.f_ext / forcesScale) @ rot.T)\n",
|
||||
"p.add_points(v_def_GD[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.1 * length_scale})\n",
|
||||
"p.add_edges(v @ rot.T, be, shading={\"line_color\": \"blue\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## BFGS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "0621481088744a34af8662b30613ceac",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-0.297981…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"3"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"report_BFGS = equilibrium_convergence_report_BFGS(solid, v_init, n_steps, 1e-8, thresh=thresh)\n",
|
||||
"energies_el_BFGS = report_BFGS['energies_el']\n",
|
||||
"energies_ext_BFGS = report_BFGS['energies_ext']\n",
|
||||
"energy_BFGS = energies_el_BFGS + energies_ext_BFGS\n",
|
||||
"residuals_BFGS = report_BFGS['residuals']\n",
|
||||
"times_BFGS = report_BFGS['times']\n",
|
||||
"idx_stop_BFGS = report_BFGS['idx_stop']\n",
|
||||
"v_def_BFGS = solid.v_def.copy()\n",
|
||||
"\n",
|
||||
"# Lastly, plot the resulting shape\n",
|
||||
"p = mp.plot(v_def_BFGS @ rot.T, solid.t, shading=shadingOptions)\n",
|
||||
"forcesScale = 2 * np.max(np.linalg.norm(solid.f_ext, axis=1))\n",
|
||||
"p.add_lines(v_def_BFGS @ rot.T, (solid.v_def + solid.f_ext / forcesScale) @ rot.T)\n",
|
||||
"p.add_points(v_def_BFGS[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.1 * length_scale})\n",
|
||||
"p.add_edges(v @ rot.T, be, shading={\"line_color\": \"blue\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Newton-CG"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Energy: -127985.65419881282 Force norm: 287742.8969935862 Line search Iters: 0\n",
|
||||
"Energy: -178892.14400109363 Force norm: 182952.00531737506 Line search Iters: 0\n",
|
||||
"Energy: -206901.42653635694 Force norm: 151950.01953001413 Line search Iters: 0\n",
|
||||
"Energy: -227792.85782151608 Force norm: 135158.66283929092 Line search Iters: 0\n",
|
||||
"Energy: -244838.85692066932 Force norm: 123433.77675577633 Line search Iters: 0\n",
|
||||
"Energy: -259318.48388755036 Force norm: 114389.35466936302 Line search Iters: 0\n",
|
||||
"Energy: -271937.0843840749 Force norm: 107190.15322070086 Line search Iters: 0\n",
|
||||
"Energy: -283160.0740997393 Force norm: 101411.77988596291 Line search Iters: 0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"report_NCG = equilibrium_convergence_report_NCG(solid, v_init, n_steps, thresh=thresh)\n",
|
||||
"energies_el_NCG = report_NCG['energies_el']\n",
|
||||
"energies_ext_NCG = report_NCG['energies_ext']\n",
|
||||
"energy_NCG = energies_el_NCG + energies_ext_NCG\n",
|
||||
"residuals_NCG = report_NCG['residuals']\n",
|
||||
"times_NCG = report_NCG['times']\n",
|
||||
"idx_stop_NCG = report_NCG['idx_stop']\n",
|
||||
"v_def_NCG = solid.v_def.copy()\n",
|
||||
"\n",
|
||||
"# Lastly, plot the resulting shape\n",
|
||||
"p = mp.plot(v_def_NCG @ rot.T, solid.t, shading=shadingOptions)\n",
|
||||
"forcesScale = 2 * np.max(np.linalg.norm(solid.f_ext, axis=1))\n",
|
||||
"p.add_lines(v_def_NCG @ rot.T, (solid.v_def + solid.f_ext / forcesScale) @ rot.T)\n",
|
||||
"p.add_points(v_def_NCG[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.1 * length_scale})\n",
|
||||
"p.add_edges(v @ rot.T, be, shading={\"line_color\": \"blue\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Compare the different algorithms"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cmap = plt.get_cmap('viridis')\n",
|
||||
"colors = cmap(np.linspace(0., 1., 4))\n",
|
||||
"\n",
|
||||
"gs = gridspec.GridSpec(nrows=1, ncols=1, width_ratios=[1], height_ratios=[1])\n",
|
||||
"fig = plt.figure(figsize=(10, 6))\n",
|
||||
"\n",
|
||||
"axTmp = plt.subplot(gs[0, 0])\n",
|
||||
"axTmp.plot(times_GD[:idx_stop_GD+1], residuals_GD[:idx_stop_GD+1], c=colors[0], \n",
|
||||
" label=\"Gradient Descent ({:}its)\".format(idx_stop_GD))\n",
|
||||
"axTmp.plot(times_BFGS[:idx_stop_BFGS+1], residuals_BFGS[:idx_stop_BFGS+1], c=colors[1], \n",
|
||||
" label=\"BFGS ({:}its)\".format(idx_stop_BFGS))\n",
|
||||
"axTmp.plot(times_NCG[:idx_stop_NCG+1], residuals_NCG[:idx_stop_NCG+1], c=colors[2], \n",
|
||||
" label=\"Newton-CG ({:}its)\".format(idx_stop_NCG))\n",
|
||||
"y_lim = axTmp.get_ylim()\n",
|
||||
"axTmp.set_title(\"Residuals as optimization goes\", fontsize=14)\n",
|
||||
"axTmp.set_xlabel(\"Computation time [s]\", fontsize=12)\n",
|
||||
"axTmp.set_ylabel(\"Force residuals [N]\", fontsize=12)\n",
|
||||
"axTmp.set_ylim(y_lim)\n",
|
||||
"plt.legend(fontsize=12)\n",
|
||||
"plt.grid()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"gs = gridspec.GridSpec(nrows=1, ncols=1, width_ratios=[1], height_ratios=[1])\n",
|
||||
"fig = plt.figure(figsize=(10, 6))\n",
|
||||
"\n",
|
||||
"axTmp = plt.subplot(gs[0, 0])\n",
|
||||
"axTmp.plot(times_GD[:idx_stop_GD+1], energy_GD[:idx_stop_GD+1], c=colors[0], \n",
|
||||
" label=\"Gradient Descent ({:}its)\".format(idx_stop_GD))\n",
|
||||
"axTmp.plot(times_BFGS[:idx_stop_BFGS+1], energy_BFGS[:idx_stop_BFGS+1], c=colors[1], \n",
|
||||
" label=\"BFGS ({:}its)\".format(idx_stop_BFGS))\n",
|
||||
"axTmp.plot(times_NCG[:idx_stop_NCG+1], energy_NCG[:idx_stop_NCG+1], c=colors[2], \n",
|
||||
" label=\"Newton-CG ({:}its)\".format(idx_stop_NCG))\n",
|
||||
"y_lim = axTmp.get_ylim()\n",
|
||||
"axTmp.set_title(\"Total energy as optimization goes\", fontsize=14)\n",
|
||||
"axTmp.set_xlabel(\"Computation time [s]\", fontsize=12)\n",
|
||||
"axTmp.set_ylabel(\"Energy [J]\", fontsize=12)\n",
|
||||
"axTmp.set_ylim(y_lim)\n",
|
||||
"plt.legend(fontsize=12)\n",
|
||||
"plt.grid()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"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"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
289
cs457-gc/assignment_2_3/notebook/test_fd.ipynb
Normal file
403
cs457-gc/assignment_2_3/src/Utils.py
Normal file
@@ -0,0 +1,403 @@
|
||||
import numpy as np
|
||||
import time
|
||||
import math
|
||||
|
||||
def conjugate_gradient(L_method, b):
|
||||
'''
|
||||
Finds an inexact Newton descent direction using Conjugate Gradient (CG)
|
||||
Solves partially L(x) = b where A is positive definite, using CG.
|
||||
The method should be take care of checking whether the added direction is
|
||||
an ascent direction or not, and whether the residuals are small enough.
|
||||
Details can be found in the handout.
|
||||
|
||||
Input:
|
||||
- L_method : a method that computes the Hessian vector product. It should
|
||||
take an array of shape (n,) and return an array of shape (n,)
|
||||
- b : right hand side of the linear system (n,)
|
||||
|
||||
Output:
|
||||
- p_star : np array of shape (n,) solving the linear system approximately
|
||||
'''
|
||||
N = b.shape[0]
|
||||
fshape = (3*N,N)
|
||||
z = np.zeros(fshape)
|
||||
r = np.zeros(fshape)
|
||||
d = np.zeros(fshape)
|
||||
alpha = np.zeros(3*N)
|
||||
beta = np.zeros(3*N)
|
||||
r[0] = -b
|
||||
d[0] = -r[0]
|
||||
ck = 0
|
||||
for k in range(0,3*N - 1):
|
||||
Ldk = L_method(d[k])
|
||||
if (d[k].T @ Ldk) <= 0:
|
||||
if (k==0):
|
||||
return b
|
||||
else:
|
||||
return z[k]
|
||||
alpha[k] = (r[k].T @ r[k])/(d[k] @ Ldk)
|
||||
z[k+1] = z[k] + alpha[k] * d[k]
|
||||
r[k+1] = r[k] + alpha[k] * Ldk
|
||||
va = np.linalg.norm(r[k+1])
|
||||
vb = math.sqrt(np.linalg.norm(b))
|
||||
if va < min(0.5,vb) * np.linalg.norm(b):
|
||||
break
|
||||
|
||||
beta[k+1] = (r[k].T @ r[k+1])/(r[k].T @ r[k])
|
||||
d[k+1] = -r[k+1] + beta[k+1]*d[k]
|
||||
ck = k
|
||||
|
||||
return z[ck+1]
|
||||
|
||||
|
||||
def compute_inverse_approximate_hessian_matrix(sk, yk, invB_prev):
|
||||
'''
|
||||
Input:
|
||||
- sk : previous step x_{k+1} - x_k, shape (n, 1)
|
||||
- yk : grad(f)_{k+1} - grad(f)_{k}, shape (n, 1)
|
||||
- invB_prev : previous Hessian estimate Bk, shape (n, n)
|
||||
|
||||
Output:
|
||||
- invB_new : previous Hessian estimate Bk, shape (n, n)
|
||||
'''
|
||||
invB_new = invB_prev.copy()
|
||||
invB_new += (sk.T @ yk + yk.T @ invB_prev @ yk) / ((sk.T @ yk) ** 2) * (sk @ sk.T)
|
||||
prod = (invB_prev @ yk) @ sk.T
|
||||
invB_new -= (prod + prod.T) / (sk.T @ yk)
|
||||
return invB_new
|
||||
|
||||
def equilibrium_convergence_report_GD(solid, v_init, n_steps, step_size, thresh=1e-3):
|
||||
'''
|
||||
Finds the equilibrium by minimizing the total energy using gradient descent.
|
||||
|
||||
Input:
|
||||
- solid : an elastic solid to optimize
|
||||
- v_init : the initial guess for the equilibrium position
|
||||
- n_step : number of optimization steps
|
||||
- step_size : scaling factor of the gradient when taking the step
|
||||
- thresh : threshold to stop the optimization process on the gradient's magnitude
|
||||
|
||||
Ouput:
|
||||
- report : a dictionary containing various quantities of interest
|
||||
'''
|
||||
|
||||
solid.update_def_shape(v_init)
|
||||
|
||||
energies_el = np.zeros(shape=(n_steps+1,))
|
||||
energies_ext = np.zeros(shape=(n_steps+1,))
|
||||
residuals = np.zeros(shape=(n_steps+1,))
|
||||
times = np.zeros(shape=(n_steps+1,))
|
||||
step_sizes = np.zeros(shape=(n_steps,))
|
||||
|
||||
energies_el[0] = solid.energy_el
|
||||
energies_ext[0] = solid.energy_ext
|
||||
residuals[0] = np.linalg.norm((solid.f + solid.f_ext)[solid.free_idx, :])
|
||||
idx_stop = n_steps
|
||||
|
||||
energy_tot_prev = energies_el[0] + energies_ext[0]
|
||||
|
||||
t_start = time.time()
|
||||
for i in range(n_steps):
|
||||
## TODO: Find the descent direction
|
||||
## descent_dir has shape (#v, 3)
|
||||
descent_dir = (solid.f + solid.f_ext)
|
||||
|
||||
|
||||
step_size_tmp = step_size
|
||||
max_l_iter = 20
|
||||
for l_iter in range(max_l_iter):
|
||||
step_size_tmp *= 0.5
|
||||
solid.displace(step_size_tmp * descent_dir)
|
||||
|
||||
## TODO: Check if the armijo rule is satisfied
|
||||
## energy_tot_tmp is the current total energy
|
||||
## armijo is a boolean that says whether the condition is satisfied
|
||||
energy_tot_tmp = solid.energy_ext + solid.energy_el
|
||||
grad_tmp = -descent_dir
|
||||
armijo = energy_tot_tmp < energy_tot_prev + thresh * step_size_tmp * ((descent_dir*grad_tmp).sum())
|
||||
|
||||
if armijo or l_iter == max_l_iter-1:
|
||||
break
|
||||
else:
|
||||
solid.displace(-step_size_tmp * descent_dir)
|
||||
step_sizes[i] = step_size_tmp
|
||||
|
||||
# Measure the force residuals
|
||||
energies_el[i+1] = solid.energy_el
|
||||
energies_ext[i+1] = solid.energy_ext
|
||||
residuals[i+1] = np.linalg.norm((solid.f + solid.f_ext)[solid.free_idx, :])
|
||||
energy_tot_prev = energy_tot_tmp
|
||||
|
||||
if residuals[i+1] < thresh:
|
||||
energies_el[i+1:] = energies_el[i+1]
|
||||
energies_ext[i+1:] = energies_ext[i+1]
|
||||
residuals[i+1:] = residuals[i+1]
|
||||
idx_stop = i
|
||||
break
|
||||
|
||||
times[i+1] = time.time() - t_start
|
||||
|
||||
report = {}
|
||||
report['energies_el'] = energies_el
|
||||
report['energies_ext'] = energies_ext
|
||||
report['residuals'] = residuals
|
||||
report['times'] = times
|
||||
report['idx_stop'] = idx_stop
|
||||
report['step_sizes'] = step_sizes
|
||||
|
||||
return report
|
||||
|
||||
|
||||
def equilibrium_convergence_report_BFGS(solid, v_init, n_steps, step_size, thresh=1e-3):
|
||||
'''
|
||||
Finds the equilibrium by minimizing the total energy using BFGS.
|
||||
|
||||
Input:
|
||||
- solid : an elastic solid to optimize
|
||||
- v_init : the initial guess for the equilibrium position
|
||||
- n_step : number of optimization steps
|
||||
- step_size : scaling factor of the direction when taking the step
|
||||
- thresh : threshold to stop the optimization process on the gradient's magnitude
|
||||
|
||||
Ouput:
|
||||
- report : a dictionary containing various quantities of interest
|
||||
'''
|
||||
|
||||
solid.update_def_shape(v_init)
|
||||
|
||||
energies_el = np.zeros(shape=(n_steps+1,))
|
||||
energies_ext = np.zeros(shape=(n_steps+1,))
|
||||
residuals = np.zeros(shape=(n_steps+1,))
|
||||
times = np.zeros(shape=(n_steps+1,))
|
||||
energies_el[0] = solid.energy_el
|
||||
energies_ext[0] = solid.energy_ext
|
||||
## TODO: Collect free vertex positions
|
||||
## grad_tmp is the current flattened gradient of the total energy
|
||||
## with respect to the free vertices
|
||||
grad_tmp = - (solid.f + solid.f_ext)[solid.free_idx,:].reshape(-1,1)
|
||||
residuals[0] = np.linalg.norm(grad_tmp)
|
||||
idx_stop = n_steps
|
||||
|
||||
energy_tot_prev = energies_el[0] + energies_ext[0]
|
||||
|
||||
|
||||
## TODO: Collect free vertex positions
|
||||
## v_tmp are the current flattened free vertices
|
||||
v_tmp = solid.v_def[solid.free_idx,:].reshape(-1,1)
|
||||
dir_zeros = np.zeros_like(solid.v_def)
|
||||
invB_prev = np.eye(v_tmp.shape[0])
|
||||
|
||||
t_start = time.time()
|
||||
for i in range(n_steps):
|
||||
|
||||
dir_tmp = - invB_prev @ grad_tmp
|
||||
dir_zeros[solid.free_idx, :] = dir_tmp.reshape(-1, 3)
|
||||
|
||||
step_size_tmp = step_size
|
||||
max_l_iter = 20
|
||||
for l_iter in range(max_l_iter):
|
||||
step_size_tmp *= 0.5
|
||||
solid.displace(step_size_tmp * dir_zeros)
|
||||
|
||||
## TODO: Check if the armijo rule is satisfied
|
||||
## energy_tot_tmp is the current total energy
|
||||
## armijo is a boolean that says whether the condition is satisfied
|
||||
energy_tot_tmp = solid.energy_el + solid.energy_ext
|
||||
armijo = energy_tot_tmp < energy_tot_prev + thresh * step_size_tmp*((dir_tmp*grad_tmp).sum())
|
||||
|
||||
if armijo or l_iter == max_l_iter-1:
|
||||
break
|
||||
else:
|
||||
solid.displace(-step_size_tmp * dir_zeros)
|
||||
|
||||
## TODO: Update all quantities
|
||||
## v_new are the new flattened free vertices
|
||||
## grad_new is the new flattened gradient of the total energy
|
||||
## with respect to the free vertices
|
||||
v_new = solid.v_def[solid.free_idx,:].reshape(-1,1)
|
||||
grad_new = - (solid.f+solid.f_ext)[solid.free_idx,:].reshape(-1,1)
|
||||
invB_prev = compute_inverse_approximate_hessian_matrix(v_new - v_tmp,
|
||||
grad_new - grad_tmp,
|
||||
invB_prev)
|
||||
v_tmp = v_new.copy()
|
||||
grad_tmp = grad_new.copy()
|
||||
|
||||
energies_el[i+1] = solid.energy_el
|
||||
energies_ext[i+1] = solid.energy_ext
|
||||
residuals[i+1] = np.linalg.norm(grad_tmp)
|
||||
|
||||
if residuals[i+1] < thresh:
|
||||
residuals[i+1:] = residuals[i+1]
|
||||
energies_el[i+1:] = energies_el[i+1]
|
||||
energies_ext[i+1:] = energies_ext[i+1]
|
||||
idx_stop = i
|
||||
break
|
||||
|
||||
times[i+1] = time.time() - t_start
|
||||
|
||||
report = {}
|
||||
report['energies_el'] = energies_el
|
||||
report['energies_ext'] = energies_ext
|
||||
report['residuals'] = residuals
|
||||
report['times'] = times
|
||||
report['idx_stop'] = idx_stop
|
||||
|
||||
return report
|
||||
|
||||
def equilibrium_convergence_report_NCG(solid, v_init, n_steps, thresh=1e-3):
|
||||
'''
|
||||
Finds the equilibrium by minimizing the total energy using Newton CG.
|
||||
|
||||
Input:
|
||||
- solid : an elastic solid to optimize
|
||||
- v_init : the initial guess for the equilibrium position
|
||||
- n_step : number of optimization steps
|
||||
- thresh : threshold to stop the optimization process on the gradient's magnitude
|
||||
|
||||
Ouput:
|
||||
- report : a dictionary containing various quantities of interest
|
||||
'''
|
||||
|
||||
solid.update_def_shape(v_init)
|
||||
|
||||
energies_el = np.zeros(shape=(n_steps+1,))
|
||||
energies_ext = np.zeros(shape=(n_steps+1,))
|
||||
residuals = np.zeros(shape=(n_steps+1,))
|
||||
times = np.zeros(shape=(n_steps+1,))
|
||||
energies_el[0] = solid.energy_el
|
||||
energies_ext[0] = solid.energy_ext
|
||||
residuals[0] = np.linalg.norm((solid.f + solid.f_ext)[solid.free_idx, :])
|
||||
idx_stop = n_steps
|
||||
|
||||
t_start = time.time()
|
||||
for i in range(n_steps):
|
||||
# Take a Newton step
|
||||
solid.equilibrium_step()
|
||||
|
||||
# Measure the force residuals
|
||||
energies_el[i+1] = solid.energy_el
|
||||
energies_ext[i+1] = solid.energy_ext
|
||||
residuals[i+1] = np.linalg.norm((solid.f + solid.f_ext)[solid.free_idx, :])
|
||||
|
||||
if residuals[i+1] < thresh:
|
||||
residuals[i+1:] = residuals[i+1]
|
||||
energies_el[i+1:] = energies_el[i+1]
|
||||
energies_ext[i+1:] = energies_ext[i+1]
|
||||
idx_stop = i
|
||||
break
|
||||
|
||||
times[i+1] = time.time() - t_start
|
||||
|
||||
report = {}
|
||||
report['energies_el'] = energies_el
|
||||
report['energies_ext'] = energies_ext
|
||||
report['residuals'] = residuals
|
||||
report['times'] = times
|
||||
report['idx_stop'] = idx_stop
|
||||
|
||||
return report
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
def fd_validation_ext(solid):
|
||||
epsilons = np.logspace(-9,-3,100)
|
||||
perturb_global = np.random.uniform(-1e-3, 1e-3, size=solid.v_def.shape)
|
||||
solid.displace(perturb_global)
|
||||
v_def = solid.v_def.copy()
|
||||
perturb = np.random.uniform(-1, 1, size=solid.v_def.shape)
|
||||
errors = []
|
||||
for eps in epsilons:
|
||||
# Back to original
|
||||
solid.update_def_shape(v_def)
|
||||
grad = np.zeros(solid.f_ext.shape)
|
||||
grad[solid.free_idx] = -solid.f_ext.copy()[solid.free_idx]
|
||||
an_delta_E = (grad*perturb).sum()
|
||||
|
||||
# One step forward
|
||||
solid.displace(perturb * eps)
|
||||
E1 = solid.energy_ext.copy()
|
||||
|
||||
# Two steps backward
|
||||
solid.displace(-2*perturb * eps)
|
||||
E2 = solid.energy_ext.copy()
|
||||
|
||||
# Compute error
|
||||
fd_delta_E = (E1 - E2)/(2*eps)
|
||||
errors.append(abs(fd_delta_E - an_delta_E)/abs(an_delta_E))
|
||||
plt.loglog(epsilons, errors)
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
def fd_validation_elastic(solid):
|
||||
epsilons = np.logspace(-9,-3,100)
|
||||
perturb_global = np.random.uniform(-1e-3, 1e-3, size=solid.v_def.shape)
|
||||
solid.displace(perturb_global)
|
||||
|
||||
v_def = solid.v_def.copy()
|
||||
solid.make_elastic_forces()
|
||||
|
||||
perturb = np.random.uniform(-1, 1, size=solid.v_def.shape)
|
||||
errors = []
|
||||
for eps in epsilons:
|
||||
# Back to original
|
||||
solid.update_def_shape(v_def)
|
||||
solid.make_elastic_forces()
|
||||
grad = np.zeros(solid.f.shape)
|
||||
grad[solid.free_idx] = -solid.f.copy()[solid.free_idx]
|
||||
an_delta_E = (grad*perturb).sum()
|
||||
|
||||
# One step forward
|
||||
solid.displace(perturb * eps)
|
||||
E1 = solid.energy_el.copy()
|
||||
|
||||
# Two steps backward
|
||||
solid.displace(-2*perturb * eps)
|
||||
E2 = solid.energy_el.copy()
|
||||
|
||||
# Compute error
|
||||
fd_delta_E = (E1 - E2)/(2*eps)
|
||||
errors.append(abs(fd_delta_E - an_delta_E)/abs(an_delta_E))
|
||||
solid.displace(perturb * eps)
|
||||
|
||||
plt.loglog(epsilons, errors)
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
def fd_validation_elastic_differentials(solid):
|
||||
epsilons = np.logspace(-9, 3,500)
|
||||
perturb_global = 1e-3*np.random.uniform(-1., 1., size=solid.v_def.shape)
|
||||
solid.displace(perturb_global)
|
||||
|
||||
v_def = solid.v_def.copy()
|
||||
|
||||
perturb = np.random.uniform(-1, 1, size=solid.v_def.shape)
|
||||
errors = []
|
||||
for eps in epsilons:
|
||||
# Back to original
|
||||
solid.update_def_shape(v_def)
|
||||
perturb_0s = np.zeros_like(perturb)
|
||||
perturb_0s[solid.free_idx] = perturb[solid.free_idx]
|
||||
an_df = solid.compute_force_differentials(perturb_0s)[solid.free_idx, :]
|
||||
an_df_full = np.zeros(solid.f.shape)
|
||||
an_df_full[solid.free_idx] = an_df.copy()
|
||||
|
||||
# One step forward
|
||||
solid.displace(perturb * eps)
|
||||
f1 = solid.f[solid.free_idx, :]
|
||||
f1_full = np.zeros(solid.f.shape)
|
||||
f1_full[solid.free_idx] = f1
|
||||
|
||||
# Two steps backward
|
||||
solid.displace(-2*perturb * eps)
|
||||
f2 = solid.f[solid.free_idx, :]
|
||||
f2_full = np.zeros(solid.f.shape)
|
||||
f2_full[solid.free_idx] = f2
|
||||
|
||||
# Compute error
|
||||
fd_delta_f = (f1_full - f2_full)/(2*eps)
|
||||
norm_an_df = np.linalg.norm(an_df_full)
|
||||
norm_error = np.linalg.norm(an_df_full - fd_delta_f)
|
||||
errors.append(norm_error/norm_an_df)
|
||||
|
||||
plt.loglog(epsilons, errors)
|
||||
plt.grid()
|
||||
plt.show()
|
163
cs457-gc/assignment_2_3/src/elasticenergy.py
Normal file
@@ -0,0 +1,163 @@
|
||||
import numpy as np
|
||||
from numpy.core.einsumfunc import einsum
|
||||
from numpy.core.fromnumeric import swapaxes
|
||||
|
||||
class ElasticEnergy:
|
||||
def __init__(self, young, poisson):
|
||||
'''
|
||||
Input:
|
||||
- young : Young's modulus [Pa]
|
||||
- poisson : Poisson ratio
|
||||
'''
|
||||
self.young = young
|
||||
self.poisson = poisson
|
||||
self.lbda = young * poisson / ((1 + poisson) * (1 - 2 * poisson))
|
||||
self.mu = young / (2 * (1 + poisson))
|
||||
|
||||
self.psi = None
|
||||
self.E = None
|
||||
self.P = None
|
||||
|
||||
self.dE = None
|
||||
self.dP = None
|
||||
|
||||
def make_energy_density(self, jac):
|
||||
'''
|
||||
This method computes the energy density at each tetrahedron (#t,),
|
||||
and stores the result in self.psi
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- psi : energy density per tet (#t,)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_strain_tensor(self, jac):
|
||||
'''
|
||||
This method computes the strain tensor (#t, 3, 3), and stores it in self.E
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- E : strain induced by the deformation (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_piola_kirchhoff_stress_tensor(self, jac):
|
||||
'''
|
||||
This method computes the stress tensor (#t, 3, 3), and stores it in self.P
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- P : stress tensor induced by the deformation (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_differential_strain_tensor(self, jac, dJac):
|
||||
'''
|
||||
This method computes the differential of strain tensor (#t, 3, 3),
|
||||
and stores it in self.dE
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
- dJac : differential of the jacobian of the deformation (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- dE : differential of the strain tensor (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_differential_piola_kirchhoff_stress_tensor(self, jac, dJac):
|
||||
'''
|
||||
This method computes the differential of the stress tensor (#t, 3, 3), and stores it in self.dP
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
- dJac : differential of the jacobian of the deformation (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- dP : differential of the stress tensor (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
class LinearElasticEnergy(ElasticEnergy):
|
||||
def __init__(self, young, poisson):
|
||||
super().__init__(young, poisson)
|
||||
|
||||
def make_energy_density(self, jac):
|
||||
fa = self.mu * np.einsum("ijk,ijk->i",self.E, self.E)
|
||||
fb = self.lbda/2.0 * np.einsum('ijj->i' ,self.E)**2
|
||||
self.psi = fa + fb
|
||||
|
||||
def make_strain_tensor(self, jac):
|
||||
self.E = (jac+np.transpose(jac,axes=(0,2,1)))/2.0 - np.identity(3)
|
||||
|
||||
def make_piola_kirchhoff_stress_tensor(self, jac):
|
||||
fa = 2.0*self.mu*self.E
|
||||
fb = self.lbda* np.einsum('i,jk->ijk',np.einsum('ijj->i',self.E), np.identity(3))
|
||||
self.P = fa + fb
|
||||
|
||||
def make_differential_strain_tensor(self, jac, dJac):
|
||||
self.dE = (dJac+np.transpose(dJac,axes=(0,2,1)))/2.0
|
||||
|
||||
def make_differential_piola_kirchhoff_stress_tensor(self, jac, dJac):
|
||||
fa = 2.0*self.mu*self.dE
|
||||
fb = self.lbda* np.einsum("i,jk->ijk",np.trace(self.dE, axis1=1,axis2=2), np.identity(3))
|
||||
self.dP = fa + fb
|
||||
|
||||
class NeoHookeanElasticEnergy(ElasticEnergy):
|
||||
def __init__(self, young, poisson):
|
||||
super().__init__(young, poisson)
|
||||
self.logJ = None
|
||||
self.Finv = None
|
||||
|
||||
def make_energy_density(self, jac):
|
||||
i1 = np.einsum('ijk,ijk->i',jac,jac)
|
||||
j = np.log(np.linalg.det(jac))
|
||||
fa = self.mu/2.0 * (i1-3 - 2*j)
|
||||
fb = self.lbda/2.0 * j**2
|
||||
self.psi = fa + fb
|
||||
|
||||
def make_strain_tensor(self, jac):
|
||||
pass
|
||||
|
||||
def make_piola_kirchhoff_stress_tensor(self, jac):
|
||||
'''
|
||||
Additional updated attributes:
|
||||
- logJ ; log of the determinant of the jacobians (#t,)
|
||||
- Finv : inverse of the jacobians (#t, 3, 3)
|
||||
'''
|
||||
self.logJ = np.log(np.linalg.det(jac))
|
||||
self.Finv = np.linalg.inv(jac)
|
||||
FinvT = np.transpose(self.Finv,axes=(0,2,1))
|
||||
fa = self.mu * (jac - FinvT)
|
||||
fb = self.lbda * np.einsum("i,ijk->ijk",self.logJ, FinvT)
|
||||
self.P = fa +fb
|
||||
|
||||
def make_differential_strain_tensor(self, jac, dJac):
|
||||
pass
|
||||
|
||||
def make_differential_piola_kirchhoff_stress_tensor(self, jac, dJac):
|
||||
self.logJ = np.log(np.linalg.det(jac))
|
||||
self.Finv = np.linalg.inv(jac)
|
||||
FinvT = np.transpose(self.Finv,axes=(0,2,1))
|
||||
dFT = np.transpose(dJac,axes=(0,2,1))
|
||||
fa = self.mu * dJac
|
||||
fb = np.einsum("i,ijk->ijk",(self.mu - self.lbda * self.logJ),FinvT @ dFT @ FinvT)
|
||||
fc = self.lbda * np.einsum("i,ijk->ijk",np.trace(self.Finv @ dJac, axis1=1,axis2=2),FinvT)
|
||||
self.dP = fa + fb + fc
|
404
cs457-gc/assignment_2_3/src/elasticsolid.py
Normal file
@@ -0,0 +1,404 @@
|
||||
import numpy as np
|
||||
from numpy import linalg
|
||||
from scipy import sparse
|
||||
from Utils import *
|
||||
import igl
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
# ELASTIC SOLID CLASS
|
||||
# -----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
class ElasticSolid(object):
|
||||
|
||||
def __init__(self, v_rest, t, ee, rho=1, pin_idx=[], f_mass=None):
|
||||
'''
|
||||
Input:
|
||||
- v_rest : position of the vertices of the mesh (#v, 3)
|
||||
- t : indices of the element's vertices (#t, 4)
|
||||
- ee : elastic energy object that can be found in elasticenergy.py
|
||||
- rho : mass per unit volume [kg.m-3]
|
||||
- pin_idx : list or np array of vertex indices to pin
|
||||
- f_mass : external force per unit mass (3,) [N.kg-1]
|
||||
'''
|
||||
|
||||
self.v_rest = v_rest.copy()
|
||||
self.v_def = v_rest.copy()
|
||||
self.t = t
|
||||
self.ee = ee
|
||||
self.rho = rho
|
||||
self.pin_idx = np.array(pin_idx)
|
||||
self.f_mass = f_mass.copy()
|
||||
self.free_idx = None
|
||||
self.pin_mask = None
|
||||
|
||||
self.W0 = None
|
||||
self.Dm = None
|
||||
self.Bm = None
|
||||
self.rest_barycenters = None
|
||||
|
||||
self.W = None
|
||||
self.Ds = None
|
||||
self.F = None
|
||||
self.def_barycenters = None
|
||||
|
||||
self.energy_el = None
|
||||
self.energy_ext = None
|
||||
|
||||
self.f = None
|
||||
self.f_vol = None
|
||||
self.f_ext = None
|
||||
|
||||
self.make_free_indices_and_pin_mask()
|
||||
self.update_rest_shape(self.v_rest)
|
||||
self.update_def_shape(self.v_def)
|
||||
|
||||
## Utils ##
|
||||
|
||||
def vertex_tet_sum(self, data):
|
||||
'''
|
||||
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 : np array of shape (#t,) or (4*#t,)
|
||||
|
||||
Output:
|
||||
- data_sum : np array of shape (#v,), containing the summed data
|
||||
'''
|
||||
i = self.t.flatten('F') # (4*#t,)
|
||||
j = np.arange(len(self.t)) # (#t,)
|
||||
j = np.tile(j, 4) # (4*#t,)
|
||||
|
||||
if len(data) == len(self.t):
|
||||
data = data[j]
|
||||
|
||||
# Has shape (#v, #t)
|
||||
m = sparse.coo_matrix((data, (i, j)), (len(self.v_rest), len(self.t)))
|
||||
return np.array(m.sum(axis=1)).flatten()
|
||||
|
||||
## Precomputation ##
|
||||
|
||||
def make_free_indices_and_pin_mask(self):
|
||||
'''
|
||||
Should list all the free indices and the pin mask.
|
||||
|
||||
Updated attributes:
|
||||
- free_index : np array of shape (#free_vertices,) containing the list of unpinned vertices
|
||||
- pin_mask : np array of shape (#v, 1) containing 1 at free vertex indices and 0 at pinned vertex indices
|
||||
'''
|
||||
self.pin_mask = np.ones((self.v_rest.shape[0],1))
|
||||
self.free_idx = np.arange(0,self.v_rest.shape[0])
|
||||
if(self.pin_idx.shape[0]<=0):
|
||||
return
|
||||
self.pin_mask[self.pin_idx] = 0
|
||||
self.free_idx = np.where(self.pin_mask==1)[0]
|
||||
|
||||
|
||||
|
||||
## Methods related to rest quantities ##
|
||||
|
||||
def make_rest_barycenters(self):
|
||||
'''
|
||||
Construct the barycenters of the undeformed configuration
|
||||
|
||||
Updated attributes:
|
||||
- rest_barycenters : np array of shape (#t, 3) containing the position of each tet's barycenter
|
||||
'''
|
||||
self.rest_barycenters = np.einsum("ijk->ik",self.v_rest[self.t])/4
|
||||
|
||||
def make_rest_shape_matrices(self):
|
||||
'''
|
||||
Construct Ds that has shape (#t, 3, 3), and its inverse Bm
|
||||
|
||||
Updated attributes:
|
||||
- Dm : np array of shape (#t, 3, 3) containing the shape matrix of each tet
|
||||
- Bm : np array of shape (#t, 3, 3) containing the inverse shape matrix of each tet
|
||||
'''
|
||||
tv = self.v_rest[self.t]
|
||||
|
||||
tva = tv[:,:3,:]
|
||||
tvb = tv[:,3,:].reshape((self.t.shape[0],1,3))
|
||||
tvb= np.repeat(tvb, 3, axis=1)
|
||||
|
||||
tvs = tva - tvb
|
||||
tvsf = np.transpose(tvs,(0,2,1))
|
||||
|
||||
self.Dm = tvsf
|
||||
self.Bm = np.linalg.inv(tvsf)
|
||||
|
||||
def update_rest_shape(self, v_rest):
|
||||
'''
|
||||
Updates the vertex position, the shape matrices Dm and Bm, the volumes W0,
|
||||
and the mass matrix at rest
|
||||
|
||||
Input:
|
||||
- v_rest : position of the vertices of the mesh at rest state (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- v_rest : np array of shape (#v, 3) containing the position of each vertex at rest
|
||||
- W0 : np array of shape (#t,) containing the signed volume of each tet
|
||||
'''
|
||||
self.v_rest = v_rest
|
||||
self.make_rest_barycenters()
|
||||
self.make_rest_shape_matrices()
|
||||
self.W0 = -np.linalg.det(self.Dm)/6
|
||||
self.update_def_shape(self.v_def)
|
||||
self.make_volumetric_and_external_forces()
|
||||
|
||||
## Methods related to deformed quantities ##
|
||||
|
||||
def make_def_barycenters(self):
|
||||
'''
|
||||
Construct the barycenters of the deformed configuration
|
||||
|
||||
Updated attributes:
|
||||
- def_barycenters : np array of shape (#t, 3) containing the position of each tet's barycenter
|
||||
'''
|
||||
self.def_barycenters = np.einsum("ijk->ik",self.v_def[self.t])/4
|
||||
|
||||
def make_def_shape_matrices(self):
|
||||
'''
|
||||
Construct Ds that has shape (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- Ds : np array of shape (#t, 3, 3) containing the shape matrix of each tet
|
||||
'''
|
||||
tv = self.v_def[self.t]
|
||||
|
||||
tva = tv[:,:3,:]
|
||||
tvb = tv[:,3,:].reshape((self.t.shape[0],1,3))
|
||||
tvb= np.repeat(tvb, 3, axis=1)
|
||||
|
||||
tvs = tva - tvb
|
||||
tvsf = np.transpose(tvs,(0,2,1))
|
||||
|
||||
self.Ds = tvsf
|
||||
|
||||
def make_jacobians(self):
|
||||
'''
|
||||
Compute the current Jacobian of the deformation
|
||||
|
||||
Updated attributes:
|
||||
- F : np array of shape (#t, 3, 3) containing Jacobian of the deformation in each tet
|
||||
'''
|
||||
self.F = self.Ds @ self.Bm # <=> np.einsum("lij,ljk->lik",self.Ds,self.Bm)
|
||||
|
||||
def update_def_shape(self, v_def):
|
||||
'''
|
||||
Updates the vertex position, the Jacobian of the deformation, and the
|
||||
resulting elastic forces.
|
||||
|
||||
Input:
|
||||
- v_def : position of the vertices of the mesh (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- v_def : np array of shape (#v, 3) containing the position of each vertex after deforming the solid
|
||||
- W : np array of shape (#t,) containing the signed volume of each tet
|
||||
'''
|
||||
self.v_def = self.v_rest
|
||||
self.v_def[self.free_idx] = v_def[self.free_idx]
|
||||
self.make_def_barycenters()
|
||||
self.make_def_shape_matrices()
|
||||
self.W = -np.linalg.det(self.Ds)/6
|
||||
self.make_jacobians()
|
||||
if(self.f_vol is None):
|
||||
self.make_volumetric_and_external_forces()
|
||||
self.make_elastic_forces()
|
||||
self.make_elastic_energy()
|
||||
self.make_external_energy()
|
||||
|
||||
def displace(self, v_disp):
|
||||
'''
|
||||
Displace the whole mesh so that v_def += v_disp
|
||||
|
||||
Input:
|
||||
- v_disp : displacement of the vertices of the mesh (#v, 3)
|
||||
'''
|
||||
self.update_def_shape(self.v_def + v_disp)
|
||||
|
||||
## Energies ##
|
||||
|
||||
def make_elastic_energy(self):
|
||||
'''
|
||||
This updates the elastic energy
|
||||
|
||||
Updated attributes:
|
||||
- energy_el : elastic energy of the system [J]
|
||||
'''
|
||||
self.ee.make_strain_tensor(self.F)
|
||||
self.ee.make_energy_density(self.F)
|
||||
self.energy_el = np.sum(self.W0 * self.ee.psi)
|
||||
|
||||
def make_external_energy(self):
|
||||
'''
|
||||
This computes the external energy potential
|
||||
|
||||
Updated attributes:
|
||||
- energy_ext : postential energy due to external forces [J]
|
||||
'''
|
||||
dx = self.def_barycenters - self.rest_barycenters
|
||||
ifv = np.einsum('i,ij -> ij', self.W0, self.f_vol)
|
||||
self.energy_ext = - np.einsum("i,ij,ij->",self.W0, self.f_vol, dx)
|
||||
|
||||
## Forces ##
|
||||
|
||||
def make_elastic_forces(self):
|
||||
'''
|
||||
This method updates the elastic forces stored in self.f (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- f : elastic forces per vertex (#v, 3)
|
||||
- ee : elastic energy, some attributes should be updated
|
||||
'''
|
||||
self.ee.make_strain_tensor(self.F)
|
||||
self.ee.make_piola_kirchhoff_stress_tensor(self.F)
|
||||
tdm = np.transpose(self.Bm,(0,2,1))
|
||||
ptdm = self.ee.P @ tdm
|
||||
f123 = -np.einsum("i,ijk->ikj",self.W0,ptdm )
|
||||
f4 = -f123[:,0] - f123[:,1] - f123[:,2]
|
||||
H = np.hstack((f123,f4[:,None]))
|
||||
|
||||
x = self.vertex_tet_sum(H[:,:,0].flatten('F'))
|
||||
y = self.vertex_tet_sum(H[:,:,1].flatten('F'))
|
||||
z = self.vertex_tet_sum(H[:,:,2].flatten('F'))
|
||||
|
||||
self.f = np.hstack((x[:,None],y[:,None],z[:,None]))
|
||||
|
||||
def make_volumetric_and_external_forces(self):
|
||||
'''
|
||||
Convert force per unit mass to volumetric forces, then distribute
|
||||
the forces to the vertices of the mesh.
|
||||
|
||||
Updated attributes:
|
||||
- f_vol : np array of shape (#t, 3) external force per unit volume acting on the tets
|
||||
- f_ext : np array of shape (#v, 3) external force acting on the vertices
|
||||
'''
|
||||
mpv = self.f_mass*self.rho
|
||||
self.f_vol = np.ones((self.W0.shape[0],1)) * mpv
|
||||
|
||||
ifv = np.einsum('i,ij -> ij', self.W0, self.f_vol)
|
||||
|
||||
f_ext_x = self.vertex_tet_sum(ifv[:,0])
|
||||
f_ext_y = self.vertex_tet_sum(ifv[:,1])
|
||||
f_ext_z = self.vertex_tet_sum(ifv[:,2])
|
||||
|
||||
self.f_ext = np.stack((f_ext_x,f_ext_y,f_ext_z),axis=1) / 4.0
|
||||
|
||||
## Force Differentials
|
||||
|
||||
def compute_force_differentials(self, v_disp):
|
||||
'''
|
||||
This computes the differential of the force given a displacement dx,
|
||||
where df = df/dx|x . dx = - K(x).dx. Where K(x) is the stiffness matrix (or Hessian)
|
||||
of the solid. Note that the implementation doesn't need to construct the stiffness matrix explicitly.
|
||||
|
||||
Input:
|
||||
- v_disp : displacement of the vertices of the mesh (#v, 3)
|
||||
|
||||
Output:
|
||||
- df : force differentials at the vertices of the mesh (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- ee : elastic energy, some attributes should be updated
|
||||
'''
|
||||
|
||||
# First compute the differential of the Jacobian
|
||||
tv = v_disp[self.t]
|
||||
tva = tv[:,:3,:]
|
||||
tvb = tv[:,3,:].reshape((-1,1,3))
|
||||
|
||||
tvb= np.repeat(tvb, 3, axis=1)
|
||||
|
||||
tvs = tva - tvb
|
||||
tvsf = np.transpose(tvs,(0,2,1))
|
||||
|
||||
dDs = tvsf
|
||||
dF = dDs @ self.Bm
|
||||
|
||||
# Then update differential quantities in self.ee
|
||||
self.ee.make_differential_strain_tensor(self.F,dF)
|
||||
self.ee.make_differential_piola_kirchhoff_stress_tensor(self.F,dF)
|
||||
|
||||
# Compute the differential of the forces
|
||||
tdm = np.transpose(self.Bm,(0,2,1))
|
||||
ptdm = self.ee.dP @ tdm
|
||||
f123 = -np.einsum("i,ijk->ikj",self.W0,ptdm)
|
||||
f4 = -f123[:,0] - f123[:,1] - f123[:,2]
|
||||
H = np.hstack((f123,f4[:,None]))
|
||||
|
||||
x = self.vertex_tet_sum(H[:,:,0].flatten('F'))
|
||||
y = self.vertex_tet_sum(H[:,:,1].flatten('F'))
|
||||
z = self.vertex_tet_sum(H[:,:,2].flatten('F'))
|
||||
|
||||
return np.hstack((x[:,None],y[:,None],z[:,None]))
|
||||
|
||||
def equilibrium_step(self, step_size_init = 2, max_l_iter = 20, c1 = 1e-4):
|
||||
'''
|
||||
This function displaces the whole solid to the next deformed configuration
|
||||
using a Newton-CG step.
|
||||
|
||||
Updated attributes:
|
||||
- LHS : The hessian vector product
|
||||
- RHS : Right hand side for the conjugate gradient linear solve
|
||||
Other than them, only attributes updated by displace(self, v_disp) should be changed
|
||||
'''
|
||||
|
||||
# Define LHS
|
||||
def LHS(dx):
|
||||
'''
|
||||
Should implement the Hessian-Vector Product L(dx), and take care of pinning constraints
|
||||
as described in the handout.
|
||||
'''
|
||||
if len(dx.shape)==1:
|
||||
dx = dx.reshape((-1,3))
|
||||
|
||||
if (dx.shape[0] < self.v_rest.shape[0]):
|
||||
dxf = np.zeros((self.v_rest.shape[0],3))
|
||||
dxf[self.free_idx] = dx
|
||||
dx = dxf
|
||||
|
||||
return -self.compute_force_differentials(dx)[self.free_idx,:].flatten()
|
||||
|
||||
self.LHS = LHS # Save to class for testing
|
||||
|
||||
# Define RHS
|
||||
RHS = (self.f + self.f_ext)[self.free_idx].flatten()
|
||||
|
||||
self.RHS = RHS # Save to class for testing
|
||||
|
||||
# Use conjugate gradient to find a descent direction
|
||||
# (see conjugate_gradient in Utils.py)
|
||||
dx_CG = conjugate_gradient(LHS,RHS).reshape(-1,3) # shape (#v, 3)
|
||||
if (dx_CG.shape[0] < self.v_rest.shape[0]):
|
||||
dxf = np.zeros((self.v_rest.shape[0],3))
|
||||
dxf[self.free_idx] = dx_CG
|
||||
dx_CG = dxf
|
||||
|
||||
# Run line search on the direction
|
||||
step_size = step_size_init
|
||||
ft = self.f + self.f_ext
|
||||
energy_tot_prev = (self.energy_el + self.energy_ext)
|
||||
for l_iter in range(max_l_iter):
|
||||
step_size *= 0.5 # DO NOT CHANGE
|
||||
dx_search = dx_CG * step_size
|
||||
self.displace(dx_search)
|
||||
|
||||
# Current force norm for unpinned vertices
|
||||
f_tmp = (self.f + self.f_ext)[self.free_idx]
|
||||
g = np.linalg.norm(f_tmp)
|
||||
|
||||
energy_tot_tmp = self.energy_el + self.energy_ext
|
||||
|
||||
#Make sure you only use the gradient of the unpinned vertices
|
||||
# USE parameter c1 = 1e-4 (from the function arguments) when you submit
|
||||
armijo = energy_tot_tmp < energy_tot_prev + c1 * step_size*(-dx_CG*dx_CG).sum()
|
||||
|
||||
if armijo or l_iter == max_l_iter-1:
|
||||
print("Energy: " + str(energy_tot_tmp) + " Force norm: " + str(g) + " Line search Iters: " + str(l_iter))
|
||||
break
|
||||
else:
|
||||
self.displace(-dx_search)
|
13
cs457-gc/assignment_2_3/src/objectives.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import numpy as np
|
||||
|
||||
def objective_target_BV(v, vt, bv):
|
||||
'''
|
||||
Input:
|
||||
- v : array of shape (#v, 3), containing the current vertices position
|
||||
- vt : array of shape (#bv, 3), containing the target surface
|
||||
- bv : boundary vertices index (#bv,)
|
||||
|
||||
Output:
|
||||
- objective : single scalar measuring the deviation from the target shape
|
||||
'''
|
||||
return 0.
|
51
cs457-gc/assignment_2_3/src/stretch_utils.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import numpy as np
|
||||
from objectives import *
|
||||
from Utils import *
|
||||
|
||||
def stretch_from_point(v, stretches, v_idx):
|
||||
'''
|
||||
Input:
|
||||
- v : vertices to be deformed (#v, 3)
|
||||
- stretches : np array of shape (3,) giving the stretching coefficients along x, y, z
|
||||
- v_idx : vertex index around which the mesh is stretched
|
||||
|
||||
Output:
|
||||
- v_stretched : deformed vertices (#v, 3)
|
||||
'''
|
||||
v_stretched = v
|
||||
return v_stretched
|
||||
|
||||
def report_stretches(solid, v_rest_init, bv, v_target, stretches, lowest_pin_idx):
|
||||
'''
|
||||
Input:
|
||||
- solid : an elastic solid to deform
|
||||
- v_rest_init : reference vertex position to compress/stretch (#v, 3)
|
||||
- bv : boundary vertices index (#bv,)
|
||||
- v_target : target boundary vertices position
|
||||
- stretches : np array of shape (n_stretches,) containing a stretch factors to try out
|
||||
- lowest_pin_idx : index of the pinned index that has the lowest z coordinate
|
||||
|
||||
Output:
|
||||
- list_v_rest : list of n_stretches rest vertex positions that have been tried out
|
||||
- list_v_eq : list of the corresponding n_stretches equilibrium vertex positions
|
||||
- target_closeness : np array of shape (n_stretches,) containing the objective values for each stretch factor
|
||||
'''
|
||||
list_v_rest = []
|
||||
list_v_eq = []
|
||||
target_closeness = np.zeros(shape=(stretches.shape[0],))
|
||||
v_rest_tmp = v_rest_init.copy()
|
||||
|
||||
for i, stretch in enumerate(stretches):
|
||||
# Compute and update the rest shape of the solid
|
||||
|
||||
# Compute new equilibrium (use the previous equilibrium state as initial guess if available)
|
||||
# You may use equilibrium_convergence_report_NCG to find the equilibrium (20 steps and thresh=1 should do)
|
||||
|
||||
# Update guess for next stretch factor
|
||||
|
||||
# Fill in the
|
||||
list_v_rest.append(solid.v_rest.copy())
|
||||
list_v_eq.append(solid.v_def.copy())
|
||||
target_closeness[i] = objective_target_BV(solid.v_def, v_target, bv)
|
||||
|
||||
return list_v_rest, list_v_eq, target_closeness
|
BIN
cs457-gc/assignment_2_3/test/dino_BFGS.png
Normal file
After Width: | Height: | Size: 497 KiB |
BIN
cs457-gc/assignment_2_3/test/dino_CG.png
Normal file
After Width: | Height: | Size: 431 KiB |