Disabled external gits

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

View File

@@ -0,0 +1,457 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Interactive Design Tool for Asymptotic Grid-Shells "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import igl\n",
"import pyvista as pv\n",
"import numpy as np\n",
"\n",
"import sys\n",
"sys.path.append('../src')\n",
"\n",
"import importlib, fabrication_helper, tracer_tool\n",
"importlib.reload(fabrication_helper)\n",
"importlib.reload(tracer_tool)\n",
"from tracer_tool import AsymptoticTracer\n",
"from fabrication_helper import FabricationHelper"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Load Mesh\n",
"Import your own mesh as an .obj.\n",
"<br>Note that the filename should not contain the file extension because it will be used as the basis for saving further data. "
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"filename = \"../data/Model01\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Initialize Interface\n",
"Don't modify this part. All parameters can be tuned with the interface."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Fabrication parameters in cm\n",
"strips_scale = 3\n",
"strips_width = 2\n",
"strips_spacing = 0.2\n",
"strips_thickness = 0.3\n",
"board_width = 60\n",
"board_length = 100\n",
"# Creation parameters\n",
"sampling_distance = 1.0\n",
"num_neighbors = 4\n",
"iter_sampling = False\n",
"# Visualisation\n",
"strips_actor = []\n",
"points_actor = []\n",
"labels_actor = []\n",
"samples_actor = {}\n",
"pathA_actor = {}\n",
"pathA_indexes = {}\n",
"pathB_actor = {}\n",
"pathB_indexes = {}\n",
"intersections = np.empty((0,3), float)\n",
"visual_scaling = 0.2\n",
"\n",
"# Initialise tracer\n",
"mesh = pv.read(filename + \".obj\")\n",
"v,f = igl.read_triangle_mesh(filename + \".obj\")\n",
"tracer = AsymptoticTracer(filename + \".obj\")\n",
"helper = FabricationHelper(strips_width, strips_thickness, strips_spacing, strips_scale)\n",
"\n",
"plot = pv.Plotter(notebook=0)\n",
"\n",
"def add_pathA(pid):\n",
" points, samples = tracer.generate_asymptotic_path(pid, True, num_neighbors, sampling_distance) \n",
"\n",
" if len(points)> 1:\n",
" pathA_actor[pid] = plot.add_mesh(pv.Spline(points, 400), color='white', line_width=10, pickable=False)\n",
" pathA_indexes[pid] = tracer.num_pathsA()-1\n",
" tracer.samples_indexes[0].append(pid)\n",
" return samples\n",
"\n",
"def add_pathB(pid):\n",
" points, samples = tracer.generate_asymptotic_path(pid, False, num_neighbors, sampling_distance) \n",
" if len(points)> 1:\n",
" pathB_actor[pid] = plot.add_mesh(pv.Spline(points, 400), color='yellow', line_width=10, pickable=False)\n",
" pathB_indexes[pid] = tracer.num_pathsB()-1\n",
" tracer.samples_indexes[1].append(pid) \n",
" return samples\n",
"\n",
"def remove_pathA(pid):\n",
" plot.remove_actor(pathA_actor[pid])\n",
" tracer.delete_path(pathA_indexes[pid], True)\n",
" del pathA_actor[pid]\n",
" #Update indexes\n",
" update_indexes(pid, True)\n",
"\n",
"def remove_pathB(pid):\n",
" plot.remove_actor(pathB_actor[pid])\n",
" tracer.delete_path(pathB_indexes[pid], False)\n",
" del pathB_actor[pid]\n",
" #Update indexes\n",
" update_indexes(pid, False)\n",
"\n",
"def add_or_delete_sample_point(pid):\n",
" orig = v[pid]\n",
"\n",
" if pid not in pathB_actor.keys() and pid not in pathA_actor.keys():\n",
" if pid in samples_actor.keys():\n",
" plot.remove_actor(samples_actor[pid])\n",
" del samples_actor[pid]\n",
" clean_intersections()\n",
" else:\n",
" if pid not in samples_actor.keys():\n",
" color = 'blue'\n",
" if tracer.flagA and not tracer.flagB:\n",
" color = 'white'\n",
" elif tracer.flagB and not tracer.flagA:\n",
" color = 'yellow'\n",
"\n",
" samples_actor[pid] = plot.add_points(np.array(orig), color=color, render_points_as_spheres=True, point_size=20.0, pickable=False)\n",
" clean_intersections()\n",
" else:\n",
" plot.remove_actor(samples_actor[pid])\n",
" color = 'blue'\n",
" if pid not in pathB_actor.keys() and pid in pathA_actor.keys():\n",
" color = 'white'\n",
" elif pid in pathB_actor.keys() and pid not in pathA_actor.keys():\n",
" color = 'yellow'\n",
" samples_actor[pid] = plot.add_points(np.array(orig), color=color, render_points_as_spheres=True, point_size=20.0, pickable=False)\n",
" clean_intersections()\n",
"\n",
"def update_indexes(path_index, first_principal_direction):\n",
" if first_principal_direction:\n",
" if path_index in pathA_indexes.keys():\n",
" del pathA_indexes[path_index]\n",
" idx = 0\n",
" for key in pathA_indexes:\n",
" pathA_indexes[key] = idx\n",
" idx+=1\n",
" else:\n",
" if path_index in pathB_indexes.keys():\n",
" del pathB_indexes[path_index]\n",
" idx = 0\n",
" for key in pathB_indexes:\n",
" pathB_indexes[key] = idx\n",
" idx+=1\n",
"\n",
"def callback_first_family(value):\n",
" tracer.flagA = value\n",
"\n",
"def callback_second_family(value):\n",
" tracer.flagB = value\n",
"\n",
"def clean_intersections():\n",
" if len(points_actor)>0:\n",
" callback_remove_labels()\n",
" plot.remove_actor(points_actor)\n",
" points_actor.clear()\n",
" labels_actor.clear()\n",
" tracer.flag_intersections = False\n",
"\n",
"def callback_intersection():\n",
" clean_intersections() \n",
" global intersections\n",
" intersections = np.empty((0,3), float)\n",
" intersections = np.append(intersections, tracer.generate_intersection_network(), axis=0)\n",
" if len(tracer.intersection_points)>0:\n",
" points_actor.append(plot.add_points(tracer.intersection_points, color='red',point_size=13.0, pickable=False)) \n",
"\n",
"def callback_flatten():\n",
" if not tracer.flag_intersections:\n",
" callback_intersection()\n",
" \n",
" helper.generate_flatten_network(tracer)\n",
" \n",
" strips_num = helper.strips_numA if helper.strips_numA > helper.strips_numB else helper.strips_numB\n",
" plot.remove_actor(strips_actor)\n",
" strips_actor.clear()\n",
" if strips_num:\n",
" for i in range(strips_num):\n",
" if i<helper.strips_numA:\n",
" points = helper.paths_flatten[0][i] * visual_scaling\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='white', width=3))\n",
" if i<helper.strips_numB:\n",
" points = helper.paths_flatten[1][i] * visual_scaling\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='yellow', width=3))\n",
" # Board boundary\n",
" points = np.array([[0.,0.,0.],[board_length*visual_scaling,0.,0.],[board_length*visual_scaling, board_width*visual_scaling,0.],[0., board_width*visual_scaling,0],[0.,0.,0.]])\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='red', width=3))\n",
" \n",
"def callback_save_indexes():\n",
" file = open(filename + \"_indexes.txt\", 'w')\n",
" for i in range(len(tracer.samples_indexes)):\n",
" for idx in tracer.samples_indexes[i]:\n",
" if i==0: \n",
" file.write(\"A\"+str(idx))\n",
" elif i==1:\n",
" file.write(\"B\"+str(idx))\n",
" file.write('\\n')\n",
" file.close()\n",
"\n",
"def callback_load_indexes():\n",
" indexes = np.loadtxt(filename + \"_indexes.txt\", dtype=str)\n",
" old_flagA = tracer.flagA\n",
" old_flagB = tracer.flagB\n",
"\n",
" for data in indexes:\n",
" pid = int(data[1:])\n",
"\n",
" tracer.flagA = True if data[0] == \"A\" else False\n",
" tracer.flagB = True if data[0] == \"B\" else False\n",
"\n",
" callback_picking(mesh,pid)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
"\n",
"def lines_from_points(points):\n",
" cells = np.empty((len(points)-1, 2), dtype=np.int_)\n",
" cells[:,0] = np.arange(0, len(points)-1, dtype=np.int_)\n",
" cells[:,1] = np.arange(1, len(points), dtype=np.int_)\n",
" cells = cells.flatten()\n",
" return np.array([points[i] for i in cells])\n",
"\n",
"def callback_picking(mesh, pid, iterative_sampling=None):\n",
"\n",
" if(iterative_sampling==None):\n",
" iterative_sampling = iter_sampling\n",
"\n",
" old_flagA = tracer.flagA\n",
" old_flagB = tracer.flagB\n",
"\n",
" # Generate first family of asymptotic curves\n",
" if tracer.flagA:\n",
" if pid in pathA_actor.keys():\n",
" remove_pathA(pid)\n",
" else:\n",
" samples = add_pathA(pid)\n",
"\n",
" if iterative_sampling:\n",
" for pt in samples:\n",
" idx = tracer.mesh.kd_tree.query(pt)[1]\n",
" tracer.flagA = False\n",
" tracer.flagB = True\n",
" callback_picking(mesh, idx, iterative_sampling=False)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
"\n",
" # Generate second family of asymptotic curves\n",
" if tracer.flagB:\n",
" if pid in pathB_actor.keys():\n",
" remove_pathB(pid)\n",
" else:\n",
" samples = add_pathB(pid)\n",
"\n",
" if iterative_sampling:\n",
" for pt in samples:\n",
" idx = tracer.mesh.kd_tree.query(pt)[1]\n",
" tracer.flagA = True\n",
" tracer.flagB = False\n",
" callback_picking(mesh, idx, iterative_sampling=False)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
" \n",
" add_or_delete_sample_point(pid)\n",
" \n",
"def callback_save_svg():\n",
" cutting_color = \"red\"\n",
" engraving_color = \"black\"\n",
" font_size = 0.4\n",
" if helper.flag_flatten==False:\n",
" helper.generate_flatten_network()\n",
" helper.generate_svg_file(filename + \"_cutting.svg\", font_size, cutting_color, engraving_color, board_length, board_width)\n",
"\n",
"def callback_width(value):\n",
" helper.strips_width = value\n",
" callback_flatten()\n",
"\n",
"def callback_board_width(value):\n",
" global board_width\n",
" board_width = value\n",
" callback_flatten()\n",
"\n",
"def callback_thickness(value):\n",
" helper.strips_thickness = value\n",
" callback_flatten()\n",
"\n",
"def callback_length(value):\n",
" helper.scale_length = value\n",
" callback_flatten()\n",
"\n",
"def callback_spacing(value):\n",
" helper.strips_spacing = value\n",
" callback_flatten()\n",
"\n",
"def callback_board_length(value):\n",
" global board_length\n",
" board_length = value\n",
" callback_flatten()\n",
"\n",
"def callback_remove_labels():\n",
" plot.remove_actor(labels_actor)\n",
" labels_actor.clear()\n",
"\n",
"def callback_add_all_labels():\n",
" callback_add_labels(True, True)\n",
"\n",
"def callback_add_labelsA():\n",
" callback_add_labels(True, False)\n",
"\n",
"def callback_add_labelsB():\n",
" callback_add_labels(False, True)\n",
" \n",
"def callback_add_labels(labelsA, labelsB):\n",
" callback_remove_labels()\n",
"\n",
" if len(tracer.paths_indexes[0])>0 and labelsA:\n",
" labels = np.core.defchararray.add('A', np.arange(len(tracer.paths_indexes[0])).astype(str))\n",
" indexes = [idx[:1][0] for idx in tracer.paths_indexes[0]]\n",
" labels_actor.append(plot.add_point_labels(tracer.paths[0][indexes], labels, font_size=22, always_visible=True, show_points=False))\n",
"\n",
" indexes = np.unique(np.array([item for sublist in tracer.intersections[0] for item in sublist[:,2]], int).flatten())\n",
" labels = np.core.defchararray.add('c', indexes.astype(str))\n",
" labels_actor.append(plot.add_point_labels(tracer.intersection_points[indexes], labels, bold=False, font_size=18, always_visible=True, show_points=False))\n",
"\n",
" if len(tracer.paths_indexes[1])>0 and labelsB:\n",
" labels = np.core.defchararray.add('B', np.arange(len(tracer.paths_indexes[1])).astype(str))\n",
" indexes = [idx[:1][0] for idx in tracer.paths_indexes[1]]\n",
" labels_actor.append(plot.add_point_labels(tracer.paths[1][indexes], labels, font_size=22, always_visible=True, show_points=False))\n",
"\n",
" indexes = np.unique(np.array([item for sublist in tracer.intersections[1] for item in sublist[:,2]], int).flatten())\n",
" labels = np.core.defchararray.add('c', indexes.astype(str))\n",
" labels_actor.append(plot.add_point_labels(tracer.intersection_points[indexes], labels, bold=False, font_size=18, always_visible=True, show_points=False))\n",
"\n",
"def callback_save_network():\n",
" file = open(filename + \"_rhino.txt\", 'w')\n",
" for i in range(2):\n",
" label = \"A\"\n",
" if i==1:\n",
" label =\"B\"\n",
"\n",
" # positions\n",
" for j in range(len(tracer.paths_indexes[i])):\n",
" path = tracer.paths_indexes[i][j]\n",
" for idx in path:\n",
" pt = tracer.paths[i][idx]\n",
" file.write(label + str(j)+ \"_\" +str(pt[0]) + \",\" + str(pt[1]) + \",\" +str(pt[2]) + \"\\n\")\n",
"\n",
" # Intersections \n",
" for i in range( len(tracer.intersection_points) ):\n",
" pt = tracer.intersection_points[i]\n",
" file.write(\"C\" + str(i) + \"_\" +str(pt[0]) + \",\" + str(pt[1]) + \",\" +str(pt[2]) + \"\\n\")\n",
" file.close()\n",
"\n",
"def callback_sampling_distance(value):\n",
" global sampling_distance\n",
" sampling_distance = value\n",
"\n",
"def callback_iterative_sampling(value):\n",
" global iter_sampling\n",
" iter_sampling = value\n",
"\n",
"plot.add_mesh(mesh, show_edges=True)\n",
"plot.add_axes()\n",
"msg = \"Press <K> for saving indexes, <L> for loading indexes or <O> to save the curve network model.\\n\"\n",
"msg += \"Press <I> for computing intersections, <J> for generating the flatten strips and <H> for saving the laser-cutting file.\\n\"\n",
"msg += \"Press <M> for hiding labels, <N> for showing all labels, <U> for showing A labels or <Y> for showing B labels.\\n\"\n",
"plot.add_text(msg, position='lower_right', font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_checkbox_button_widget(callback_first_family, value=tracer.flagA, position=(10, 200.0), size=40, border_size=1, color_on='white', color_off='grey', background_color='red')\n",
"plot.add_checkbox_button_widget(callback_second_family, value=tracer.flagB, position=(10, 300.0), size=40, border_size=1, color_on='yellow', color_off='grey', background_color='red')\n",
"plot.add_checkbox_button_widget(callback_iterative_sampling, value=iter_sampling, position=(10, 400.0), size=40, border_size=1, color_on='green', color_off='grey', background_color='red')\n",
"plot.add_text(\"First Family\", position=(80.0, 200.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_text(\"Second Family\", position=(80, 300.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_text(\"Iterative sampling\", position=(80, 400.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_key_event('i', callback_intersection)\n",
"plot.add_key_event('j', callback_flatten)\n",
"plot.add_key_event('k', callback_save_indexes)\n",
"plot.add_key_event('l', callback_load_indexes)\n",
"plot.add_key_event('h', callback_save_svg)\n",
"plot.add_key_event('m', callback_remove_labels)\n",
"plot.add_key_event('n', callback_add_all_labels)\n",
"plot.add_key_event('u', callback_add_labelsA)\n",
"plot.add_key_event('y', callback_add_labelsB)\n",
"plot.add_key_event('o', callback_save_network)\n",
"plot.enable_point_picking(callback=callback_picking, show_message=True, color='pink', point_size=10, use_mesh=True, show_point=True)\n",
"plot.add_slider_widget(callback_width, [0.1, 5.0], value=strips_width, title=\"Strip Width (cm)\", pointa=(.83, .15), pointb=(.98, .15), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_thickness, [0.1, 1], value=strips_thickness, title=\"Strip Thickness (cm)\", pointa=(.67, .15), pointb=(.82, .15), title_height=0.02, fmt=\"%0.2f\", style='modern')\n",
"plot.add_slider_widget(callback_length, [1, 10], value=strips_scale, title=\"Scale Strip Length\", pointa=(.51, .15), pointb=(.66, .15), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_spacing, [0., 0.5], value=strips_spacing, title=\"Strip spacing\", pointa=(.51, .88), pointb=(.66, .88), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_board_width, [10, 100], value=board_width, title=\"Board width (cm)\", pointa=(.67, .88), pointb=(.82, .88), title_height=0.02, fmt=\"%0.0f\", style='modern')\n",
"plot.add_slider_widget(callback_board_length, [10, 100], value=board_length, title=\"Board length (cm)\", pointa=(.83, .88), pointb=(.98, .88), title_height=0.02, fmt=\"%0.0f\", style='modern')\n",
"plot.add_slider_widget(callback_sampling_distance, [0.1, 2.0], value=sampling_distance, title=\"Sampling distance\", pointa=(.005, .88), pointb=(.16, .88), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.show(\"Asymptotic GridShell\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"interpreter": {
"hash": "294c9a689e437aa1430c5ffd3595515046a5cee981399d48a2291c079c814bc8"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@@ -0,0 +1,171 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from meshplot import plot"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"sys.path.append('../src')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import importlib, tracer_helper, tracer_utils\n",
"importlib.reload(tracer_helper)\n",
"importlib.reload(tracer_utils)\n",
"from tracer_utils import asymptotic_path\n",
"from tracer_helper import Mesh"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example\n",
"Build mesh from file"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f19ce42be2f6405796de381ba4b89b42",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Renderer(camera=PerspectiveCamera(aspect=1.5, children=(DirectionalLight(color='white', intensity=0.6, positio…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"mesh = Mesh(\"../data/Model01.obj\")\n",
"p = plot(mesh.V, mesh.F, shading={\"wireframe\": True,\"width\": 900, \"height\": 600}, return_plot=True, c=np.array([0,0.7,1]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Trace first asymptotic curve\n",
"Use principal directions V1"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Set tracing parameters\n",
"num_steps = 1000\n",
"step_size = 1e-6\n",
"num_neighbors = 4\n",
"first_principal_direction = False\n",
"\n",
"# Pre-selection of vertices\n",
"idxA = [167,173,178,146,159,291,49,40,254,57,15,65,268,341,283]\n",
"# Tracing\n",
"for idx in idxA:\n",
" P, A, PP = asymptotic_path(idx, mesh, num_steps, step_size, first_principal_direction, num_neighbors)\n",
"\n",
" # Plot starting vertex\n",
" p.add_points(np.array([mesh.V[idx]]), shading={\"point_size\": 0.7, \"point_color\": \"black\"})\n",
" # Plot edge-points shaping the asymptotic path\n",
" p.add_points(P, shading={\"point_size\": 0.2,\"point_color\": \"white\"})\n",
" # Plot asymptotic curve\n",
" if(len(P)>1): \n",
" p.add_lines(P[:-1], P[1:], shading={\"line_color\": \"white\"})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Trace second asymptotic curve\n",
"Use principal directions V2"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Set tracing parameters\n",
"num_steps = 1000\n",
"step_size = 1e-6\n",
"num_neighbors = 4\n",
"first_principal_direction = True\n",
"\n",
"# Pre-selection of vertices\n",
"idxB = [119,203,188,129,95,66,308,298,290,282,335,143,81,73,33]\n",
"# Tracing\n",
"for idx in idxB:\n",
" P, A, PP = asymptotic_path(idx, mesh, num_steps, step_size, first_principal_direction, num_neighbors)\n",
" \n",
" # Plot starting vertex\n",
" p.add_points(np.array([mesh.V[idx]]), shading={\"point_size\": 0.7, \"point_color\": \"black\"})\n",
" # Plot edge-points shaping the asymptotic path\n",
" p.add_points(P, shading={\"point_size\": 0.2,\"point_color\": \"yellow\"})\n",
" # Plot asymptotic curve\n",
" if(len(P)>1): \n",
" p.add_lines(P[:-1], P[1:], shading={\"line_color\": \"yellow\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"interpreter": {
"hash": "d74ce2d711eca57e47550fdd427f707c5faa08517318f0967f4aae699c902c0e"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@@ -0,0 +1,509 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Interactive Design Tool for Asymptotic Grid-Shells "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import igl\n",
"import pyvista as pv\n",
"import numpy as np\n",
"\n",
"import sys\n",
"sys.path.append('../src')\n",
"\n",
"import importlib, fabrication_helper, tracer_tool\n",
"importlib.reload(fabrication_helper)\n",
"importlib.reload(tracer_tool)\n",
"from tracer_tool import AsymptoticTracer\n",
"from fabrication_helper import FabricationHelper"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Load Mesh\n",
"Import your own mesh as an .obj.\n",
"<br>Note that the filename should not contain the file extension because it will be used as the basis for saving further data. "
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"filename = \"../data/final\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Initialize Interface\n",
"Don't modify this part. All parameters can be tuned with the interface."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hit Boundary\n",
"Duplicate Point\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Duplicate Point\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Duplicate Point\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n"
]
}
],
"source": [
"# Fabrication parameters in cm\n",
"strips_scale = 3\n",
"strips_width = 2\n",
"strips_spacing = 0.2\n",
"strips_thickness = 0.3\n",
"board_width = 60\n",
"board_length = 100\n",
"# Creation parameters\n",
"sampling_distance = 1.0\n",
"num_neighbors = 4\n",
"iter_sampling = False\n",
"# Visualisation\n",
"strips_actor = []\n",
"points_actor = []\n",
"labels_actor = []\n",
"samples_actor = {}\n",
"pathA_actor = {}\n",
"pathA_indexes = {}\n",
"pathB_actor = {}\n",
"pathB_indexes = {}\n",
"intersections = np.empty((0,3), float)\n",
"visual_scaling = 0.2\n",
"\n",
"# Initialise tracer\n",
"mesh = pv.read(filename + \".obj\")\n",
"v,f = igl.read_triangle_mesh(filename + \".obj\")\n",
"tracer = AsymptoticTracer(filename + \".obj\")\n",
"helper = FabricationHelper(strips_width, strips_thickness, strips_spacing, strips_scale)\n",
"\n",
"plot = pv.Plotter(notebook=0)\n",
"\n",
"def add_pathA(pid):\n",
" points, samples = tracer.generate_asymptotic_path(pid, True, num_neighbors, sampling_distance) \n",
"\n",
" if len(points)> 1:\n",
" pathA_actor[pid] = plot.add_mesh(pv.Spline(points, 400), color='white', line_width=10, pickable=False)\n",
" pathA_indexes[pid] = tracer.num_pathsA()-1\n",
" tracer.samples_indexes[0].append(pid)\n",
" return samples\n",
"\n",
"def add_pathB(pid):\n",
" points, samples = tracer.generate_asymptotic_path(pid, False, num_neighbors, sampling_distance) \n",
" if len(points)> 1:\n",
" pathB_actor[pid] = plot.add_mesh(pv.Spline(points, 400), color='yellow', line_width=10, pickable=False)\n",
" pathB_indexes[pid] = tracer.num_pathsB()-1\n",
" tracer.samples_indexes[1].append(pid) \n",
" return samples\n",
"\n",
"def remove_pathA(pid):\n",
" plot.remove_actor(pathA_actor[pid])\n",
" tracer.delete_path(pathA_indexes[pid], True)\n",
" del pathA_actor[pid]\n",
" #Update indexes\n",
" update_indexes(pid, True)\n",
"\n",
"def remove_pathB(pid):\n",
" plot.remove_actor(pathB_actor[pid])\n",
" tracer.delete_path(pathB_indexes[pid], False)\n",
" del pathB_actor[pid]\n",
" #Update indexes\n",
" update_indexes(pid, False)\n",
"\n",
"def add_or_delete_sample_point(pid):\n",
" orig = v[pid]\n",
"\n",
" if pid not in pathB_actor.keys() and pid not in pathA_actor.keys():\n",
" if pid in samples_actor.keys():\n",
" plot.remove_actor(samples_actor[pid])\n",
" del samples_actor[pid]\n",
" clean_intersections()\n",
" else:\n",
" if pid not in samples_actor.keys():\n",
" color = 'blue'\n",
" if tracer.flagA and not tracer.flagB:\n",
" color = 'white'\n",
" elif tracer.flagB and not tracer.flagA:\n",
" color = 'yellow'\n",
"\n",
" samples_actor[pid] = plot.add_points(np.array(orig), color=color, render_points_as_spheres=True, point_size=20.0, pickable=False)\n",
" clean_intersections()\n",
" else:\n",
" plot.remove_actor(samples_actor[pid])\n",
" color = 'blue'\n",
" if pid not in pathB_actor.keys() and pid in pathA_actor.keys():\n",
" color = 'white'\n",
" elif pid in pathB_actor.keys() and pid not in pathA_actor.keys():\n",
" color = 'yellow'\n",
" samples_actor[pid] = plot.add_points(np.array(orig), color=color, render_points_as_spheres=True, point_size=20.0, pickable=False)\n",
" clean_intersections()\n",
"\n",
"def update_indexes(path_index, first_principal_direction):\n",
" if first_principal_direction:\n",
" if path_index in pathA_indexes.keys():\n",
" del pathA_indexes[path_index]\n",
" idx = 0\n",
" for key in pathA_indexes:\n",
" pathA_indexes[key] = idx\n",
" idx+=1\n",
" else:\n",
" if path_index in pathB_indexes.keys():\n",
" del pathB_indexes[path_index]\n",
" idx = 0\n",
" for key in pathB_indexes:\n",
" pathB_indexes[key] = idx\n",
" idx+=1\n",
"\n",
"def callback_first_family(value):\n",
" tracer.flagA = value\n",
"\n",
"def callback_second_family(value):\n",
" tracer.flagB = value\n",
"\n",
"def clean_intersections():\n",
" if len(points_actor)>0:\n",
" callback_remove_labels()\n",
" plot.remove_actor(points_actor)\n",
" points_actor.clear()\n",
" labels_actor.clear()\n",
" tracer.flag_intersections = False\n",
"\n",
"def callback_intersection():\n",
" clean_intersections() \n",
" global intersections\n",
" intersections = np.empty((0,3), float)\n",
" intersections = np.append(intersections, tracer.generate_intersection_network(), axis=0)\n",
" if len(tracer.intersection_points)>0:\n",
" points_actor.append(plot.add_points(tracer.intersection_points, color='red',point_size=13.0, pickable=False)) \n",
"\n",
"def callback_flatten():\n",
" if not tracer.flag_intersections:\n",
" callback_intersection()\n",
" \n",
" helper.generate_flatten_network(tracer)\n",
" \n",
" strips_num = helper.strips_numA if helper.strips_numA > helper.strips_numB else helper.strips_numB\n",
" plot.remove_actor(strips_actor)\n",
" strips_actor.clear()\n",
" if strips_num:\n",
" for i in range(strips_num):\n",
" if i<helper.strips_numA:\n",
" points = helper.paths_flatten[0][i] * visual_scaling\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='white', width=3))\n",
" if i<helper.strips_numB:\n",
" points = helper.paths_flatten[1][i] * visual_scaling\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='yellow', width=3))\n",
" # Board boundary\n",
" points = np.array([[0.,0.,0.],[board_length*visual_scaling,0.,0.],[board_length*visual_scaling, board_width*visual_scaling,0.],[0., board_width*visual_scaling,0],[0.,0.,0.]])\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='red', width=3))\n",
" \n",
"def callback_save_indexes():\n",
" file = open(filename + \"_indexes.txt\", 'w')\n",
" for i in range(len(tracer.samples_indexes)):\n",
" for idx in tracer.samples_indexes[i]:\n",
" if i==0: \n",
" file.write(\"A\"+str(idx))\n",
" elif i==1:\n",
" file.write(\"B\"+str(idx))\n",
" file.write('\\n')\n",
" file.close()\n",
"\n",
"def callback_load_indexes():\n",
" indexes = np.loadtxt(filename + \"_indexes.txt\", dtype=str)\n",
" old_flagA = tracer.flagA\n",
" old_flagB = tracer.flagB\n",
"\n",
" for data in indexes:\n",
" pid = int(data[1:])\n",
"\n",
" tracer.flagA = True if data[0] == \"A\" else False\n",
" tracer.flagB = True if data[0] == \"B\" else False\n",
"\n",
" callback_picking(mesh,pid)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
"\n",
"def lines_from_points(points):\n",
" cells = np.empty((len(points)-1, 2), dtype=np.int_)\n",
" cells[:,0] = np.arange(0, len(points)-1, dtype=np.int_)\n",
" cells[:,1] = np.arange(1, len(points), dtype=np.int_)\n",
" cells = cells.flatten()\n",
" return np.array([points[i] for i in cells])\n",
"\n",
"def callback_picking(mesh, pid, iterative_sampling=None):\n",
"\n",
" if(iterative_sampling==None):\n",
" iterative_sampling = iter_sampling\n",
"\n",
" old_flagA = tracer.flagA\n",
" old_flagB = tracer.flagB\n",
"\n",
" # Generate first family of asymptotic curves\n",
" if tracer.flagA:\n",
" if pid in pathA_actor.keys():\n",
" remove_pathA(pid)\n",
" else:\n",
" samples = add_pathA(pid)\n",
"\n",
" if iterative_sampling:\n",
" for pt in samples:\n",
" idx = tracer.mesh.kd_tree.query(pt)[1]\n",
" tracer.flagA = False\n",
" tracer.flagB = True\n",
" callback_picking(mesh, idx, iterative_sampling=False)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
"\n",
" # Generate second family of asymptotic curves\n",
" if tracer.flagB:\n",
" if pid in pathB_actor.keys():\n",
" remove_pathB(pid)\n",
" else:\n",
" samples = add_pathB(pid)\n",
"\n",
" if iterative_sampling:\n",
" for pt in samples:\n",
" idx = tracer.mesh.kd_tree.query(pt)[1]\n",
" tracer.flagA = True\n",
" tracer.flagB = False\n",
" callback_picking(mesh, idx, iterative_sampling=False)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
" \n",
" add_or_delete_sample_point(pid)\n",
" \n",
"def callback_save_svg():\n",
" cutting_color = \"red\"\n",
" engraving_color = \"black\"\n",
" font_size = 0.4\n",
" if helper.flag_flatten==False:\n",
" helper.generate_flatten_network()\n",
" helper.generate_svg_file(filename + \"_cutting.svg\", font_size, cutting_color, engraving_color, board_length, board_width)\n",
"\n",
"def callback_width(value):\n",
" helper.strips_width = value\n",
" callback_flatten()\n",
"\n",
"def callback_board_width(value):\n",
" global board_width\n",
" board_width = value\n",
" callback_flatten()\n",
"\n",
"def callback_thickness(value):\n",
" helper.strips_thickness = value\n",
" callback_flatten()\n",
"\n",
"def callback_length(value):\n",
" helper.scale_length = value\n",
" callback_flatten()\n",
"\n",
"def callback_spacing(value):\n",
" helper.strips_spacing = value\n",
" callback_flatten()\n",
"\n",
"def callback_board_length(value):\n",
" global board_length\n",
" board_length = value\n",
" callback_flatten()\n",
"\n",
"def callback_remove_labels():\n",
" plot.remove_actor(labels_actor)\n",
" labels_actor.clear()\n",
"\n",
"def callback_add_all_labels():\n",
" callback_add_labels(True, True)\n",
"\n",
"def callback_add_labelsA():\n",
" callback_add_labels(True, False)\n",
"\n",
"def callback_add_labelsB():\n",
" callback_add_labels(False, True)\n",
" \n",
"def callback_add_labels(labelsA, labelsB):\n",
" callback_remove_labels()\n",
"\n",
" if len(tracer.paths_indexes[0])>0 and labelsA:\n",
" labels = np.core.defchararray.add('A', np.arange(len(tracer.paths_indexes[0])).astype(str))\n",
" indexes = [idx[:1][0] for idx in tracer.paths_indexes[0]]\n",
" labels_actor.append(plot.add_point_labels(tracer.paths[0][indexes], labels, font_size=22, always_visible=True, show_points=False))\n",
"\n",
" indexes = np.unique(np.array([item for sublist in tracer.intersections[0] for item in sublist[:,2]], int).flatten())\n",
" labels = np.core.defchararray.add('c', indexes.astype(str))\n",
" labels_actor.append(plot.add_point_labels(tracer.intersection_points[indexes], labels, bold=False, font_size=18, always_visible=True, show_points=False))\n",
"\n",
" if len(tracer.paths_indexes[1])>0 and labelsB:\n",
" labels = np.core.defchararray.add('B', np.arange(len(tracer.paths_indexes[1])).astype(str))\n",
" indexes = [idx[:1][0] for idx in tracer.paths_indexes[1]]\n",
" labels_actor.append(plot.add_point_labels(tracer.paths[1][indexes], labels, font_size=22, always_visible=True, show_points=False))\n",
"\n",
" indexes = np.unique(np.array([item for sublist in tracer.intersections[1] for item in sublist[:,2]], int).flatten())\n",
" labels = np.core.defchararray.add('c', indexes.astype(str))\n",
" labels_actor.append(plot.add_point_labels(tracer.intersection_points[indexes], labels, bold=False, font_size=18, always_visible=True, show_points=False))\n",
"\n",
"def callback_save_network():\n",
" file = open(filename + \"_rhino.txt\", 'w')\n",
" for i in range(2):\n",
" label = \"A\"\n",
" if i==1:\n",
" label =\"B\"\n",
"\n",
" # positions\n",
" for j in range(len(tracer.paths_indexes[i])):\n",
" path = tracer.paths_indexes[i][j]\n",
" for idx in path:\n",
" pt = tracer.paths[i][idx]\n",
" file.write(label + str(j)+ \"_\" +str(pt[0]) + \",\" + str(pt[1]) + \",\" +str(pt[2]) + \"\\n\")\n",
"\n",
" # Intersections \n",
" for i in range( len(tracer.intersection_points) ):\n",
" pt = tracer.intersection_points[i]\n",
" file.write(\"C\" + str(i) + \"_\" +str(pt[0]) + \",\" + str(pt[1]) + \",\" +str(pt[2]) + \"\\n\")\n",
" file.close()\n",
"\n",
"def callback_sampling_distance(value):\n",
" global sampling_distance\n",
" sampling_distance = value\n",
"\n",
"def callback_iterative_sampling(value):\n",
" global iter_sampling\n",
" iter_sampling = value\n",
"\n",
"plot.add_mesh(mesh, show_edges=True)\n",
"plot.add_axes()\n",
"msg = \"Press <K> for saving indexes, <L> for loading indexes or <O> to save the curve network model.\\n\"\n",
"msg += \"Press <I> for computing intersections, <J> for generating the flatten strips and <H> for saving the laser-cutting file.\\n\"\n",
"msg += \"Press <M> for hiding labels, <N> for showing all labels, <U> for showing A labels or <Y> for showing B labels.\\n\"\n",
"plot.add_text(msg, position='lower_right', font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_checkbox_button_widget(callback_first_family, value=tracer.flagA, position=(10, 200.0), size=40, border_size=1, color_on='white', color_off='grey', background_color='red')\n",
"plot.add_checkbox_button_widget(callback_second_family, value=tracer.flagB, position=(10, 300.0), size=40, border_size=1, color_on='yellow', color_off='grey', background_color='red')\n",
"plot.add_checkbox_button_widget(callback_iterative_sampling, value=iter_sampling, position=(10, 400.0), size=40, border_size=1, color_on='green', color_off='grey', background_color='red')\n",
"plot.add_text(\"First Family\", position=(80.0, 200.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_text(\"Second Family\", position=(80, 300.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_text(\"Iterative sampling\", position=(80, 400.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_key_event('i', callback_intersection)\n",
"plot.add_key_event('j', callback_flatten)\n",
"plot.add_key_event('k', callback_save_indexes)\n",
"plot.add_key_event('l', callback_load_indexes)\n",
"plot.add_key_event('h', callback_save_svg)\n",
"plot.add_key_event('m', callback_remove_labels)\n",
"plot.add_key_event('n', callback_add_all_labels)\n",
"plot.add_key_event('u', callback_add_labelsA)\n",
"plot.add_key_event('y', callback_add_labelsB)\n",
"plot.add_key_event('o', callback_save_network)\n",
"plot.enable_point_picking(callback=callback_picking, show_message=True, color='pink', point_size=10, use_mesh=True, show_point=True)\n",
"plot.add_slider_widget(callback_width, [0.1, 5.0], value=strips_width, title=\"Strip Width (cm)\", pointa=(.83, .15), pointb=(.98, .15), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_thickness, [0.1, 1], value=strips_thickness, title=\"Strip Thickness (cm)\", pointa=(.67, .15), pointb=(.82, .15), title_height=0.02, fmt=\"%0.2f\", style='modern')\n",
"plot.add_slider_widget(callback_length, [1, 10], value=strips_scale, title=\"Scale Strip Length\", pointa=(.51, .15), pointb=(.66, .15), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_spacing, [0., 0.5], value=strips_spacing, title=\"Strip spacing\", pointa=(.51, .88), pointb=(.66, .88), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_board_width, [10, 100], value=board_width, title=\"Board width (cm)\", pointa=(.67, .88), pointb=(.82, .88), title_height=0.02, fmt=\"%0.0f\", style='modern')\n",
"plot.add_slider_widget(callback_board_length, [10, 100], value=board_length, title=\"Board length (cm)\", pointa=(.83, .88), pointb=(.98, .88), title_height=0.02, fmt=\"%0.0f\", style='modern')\n",
"plot.add_slider_widget(callback_sampling_distance, [0.1, 2.0], value=sampling_distance, title=\"Sampling distance\", pointa=(.005, .88), pointb=(.16, .88), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.show(\"Asymptotic GridShell\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"interpreter": {
"hash": "294c9a689e437aa1430c5ffd3595515046a5cee981399d48a2291c079c814bc8"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@@ -0,0 +1,171 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from meshplot import plot"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"sys.path.append('../src')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import importlib, tracer_helper, tracer_utils\n",
"importlib.reload(tracer_helper)\n",
"importlib.reload(tracer_utils)\n",
"from tracer_utils import asymptotic_path\n",
"from tracer_helper import Mesh"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example\n",
"Build mesh from file"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f19ce42be2f6405796de381ba4b89b42",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Renderer(camera=PerspectiveCamera(aspect=1.5, children=(DirectionalLight(color='white', intensity=0.6, positio…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"mesh = Mesh(\"../data/Model01.obj\")\n",
"p = plot(mesh.V, mesh.F, shading={\"wireframe\": True,\"width\": 900, \"height\": 600}, return_plot=True, c=np.array([0,0.7,1]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Trace first asymptotic curve\n",
"Use principal directions V1"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Set tracing parameters\n",
"num_steps = 1000\n",
"step_size = 1e-6\n",
"num_neighbors = 4\n",
"first_principal_direction = False\n",
"\n",
"# Pre-selection of vertices\n",
"idxA = [167,173,178,146,159,291,49,40,254,57,15,65,268,341,283]\n",
"# Tracing\n",
"for idx in idxA:\n",
" P, A, PP = asymptotic_path(idx, mesh, num_steps, step_size, first_principal_direction, num_neighbors)\n",
"\n",
" # Plot starting vertex\n",
" p.add_points(np.array([mesh.V[idx]]), shading={\"point_size\": 0.7, \"point_color\": \"black\"})\n",
" # Plot edge-points shaping the asymptotic path\n",
" p.add_points(P, shading={\"point_size\": 0.2,\"point_color\": \"white\"})\n",
" # Plot asymptotic curve\n",
" if(len(P)>1): \n",
" p.add_lines(P[:-1], P[1:], shading={\"line_color\": \"white\"})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Trace second asymptotic curve\n",
"Use principal directions V2"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# Set tracing parameters\n",
"num_steps = 1000\n",
"step_size = 1e-6\n",
"num_neighbors = 4\n",
"first_principal_direction = True\n",
"\n",
"# Pre-selection of vertices\n",
"idxB = [119,203,188,129,95,66,308,298,290,282,335,143,81,73,33]\n",
"# Tracing\n",
"for idx in idxB:\n",
" P, A, PP = asymptotic_path(idx, mesh, num_steps, step_size, first_principal_direction, num_neighbors)\n",
" \n",
" # Plot starting vertex\n",
" p.add_points(np.array([mesh.V[idx]]), shading={\"point_size\": 0.7, \"point_color\": \"black\"})\n",
" # Plot edge-points shaping the asymptotic path\n",
" p.add_points(P, shading={\"point_size\": 0.2,\"point_color\": \"yellow\"})\n",
" # Plot asymptotic curve\n",
" if(len(P)>1): \n",
" p.add_lines(P[:-1], P[1:], shading={\"line_color\": \"yellow\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"interpreter": {
"hash": "d74ce2d711eca57e47550fdd427f707c5faa08517318f0967f4aae699c902c0e"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}