{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import open3d as o3d\n",
    "import os\n",
    "import sys\n",
    "\n",
    "# monkey patches visualization and provides helpers to load geometries\n",
    "sys.path.append('..')\n",
    "import open3d_tutorial as o3dtut\n",
    "# change to True if you want to interact with the visualization windows\n",
    "o3dtut.interactive = not \"CI\" in os.environ"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Half Edge Mesh\n",
    "\n",
    "This tutorial outlines the following:\n",
    "1. How to use `mesh_show_back_face` to render the backface of a mesh.\n",
    "2. How to use `geometry.AxisAlignedBoundingBox` to crop a mesh. \n",
    "3. How to use `utility.Vector3dVector` to colorize boundary vertices of a mesh to red. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Render the backface of a Mesh\n",
    "\n",
    "In order to render the backface of a mesh `visualization.draw_geometries()` is called with the flag `mesh_show_back_face` set to `True`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {},
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Initialize a HalfEdgeTriangleMesh from TriangleMesh\n",
    "mesh = o3d.geometry.TriangleMesh.create_sphere()\n",
    "bbox = o3d.geometry.AxisAlignedBoundingBox()\n",
    "bbox.min_bound = [-1, -1, -1]\n",
    "bbox.max_bound = [1, 0.6, 1]\n",
    "mesh = mesh.crop(bbox)\n",
    "het_mesh = o3d.geometry.HalfEdgeTriangleMesh.create_from_triangle_mesh(mesh)\n",
    "o3d.visualization.draw_geometries([het_mesh], mesh_show_back_face=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Cropping a Mesh\n",
    "\n",
    "`geometry.AxisAlignedBoundingBox` is used to create an axis aligned box. The parameters `min_bound` and `max_bound` take an array of cartesian coordinates (x,y,z) and define the size of the bounding box. The bounds are set such that the y-axis of the sphere mesh is cut by a call to `crop`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {},
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Colorize boundary vertices to red\n",
    "vertex_colors = 0.75 * np.ones((len(het_mesh.vertices), 3))\n",
    "for boundary in het_mesh.get_boundaries():\n",
    "    for vertex_id in boundary:\n",
    "        vertex_colors[vertex_id] = [1, 0, 0]\n",
    "het_mesh.vertex_colors = o3d.utility.Vector3dVector(vertex_colors)\n",
    "o3d.visualization.draw_geometries([het_mesh], mesh_show_back_face=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Colorize the Boundaries of a Mesh\n",
    "\n",
    "A call to `geometry.TriangleMesh.get_boundaries` returns a vector of boundaries, where each boundary is a vector of vertices. Each vertex color is represented by an RBG array and `Vector3dVector` is used to convert `vertex_colors` of shape (n, 3) to Open3D format. Finally, the vertex colors are set on the mesh."
   ]
  }
 ],
 "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.8.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
