{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "nbsphinx": "hidden"
   },
   "outputs": [],
   "source": [
    "import open3d as o3d\n",
    "import numpy as np\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": [
    "# Working with NumPy\n",
    "All data structures in Open3D are natively compatible with a [NumPy](https://numpy.org/) buffer. The following tutorial generates a variant of sync function using NumPy and visualizes the function using Open3D.\n",
    "\n",
    "First, we generate a $n \\times 3$ matrix `xyz`. Each column has $x$, $y$, and $z$ values of the function $z = \\frac{sin(x^2 + y^2)}{x^2 + y^2}$. $z_\\text{norm}$ is the normalized map of $z$ for the [0,1] range."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Generate some neat n times 3 matrix using a variant of sync function\n",
    "x = np.linspace(-3, 3, 401)\n",
    "mesh_x, mesh_y = np.meshgrid(x, x)\n",
    "z = np.sinc((np.power(mesh_x, 2) + np.power(mesh_y, 2)))\n",
    "z_norm = (z - z.min()) / (z.max() - z.min())\n",
    "xyz = np.zeros((np.size(mesh_x), 3))\n",
    "xyz[:, 0] = np.reshape(mesh_x, -1)\n",
    "xyz[:, 1] = np.reshape(mesh_y, -1)\n",
    "xyz[:, 2] = np.reshape(z_norm, -1)\n",
    "print('xyz')\n",
    "print(xyz)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## From NumPy to open3d.PointCloud\n",
    "Open3D provides conversion from a NumPy matrix to a vector of 3D vectors. By using `Vector3dVector`, a NumPy matrix can be directly assigned to `open3d.PointCloud.points`.\n",
    "\n",
    "In this manner, any similar data structure such as `open3d.PointCloud.colors` or `open3d.PointCloud.normals` can be assigned or modified using NumPy. The code below also saves the point cloud as a `ply` file for the next step."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Pass xyz to Open3D.o3d.geometry.PointCloud and visualize\n",
    "pcd = o3d.geometry.PointCloud()\n",
    "pcd.points = o3d.utility.Vector3dVector(xyz)\n",
    "o3d.io.write_point_cloud(\"sync.ply\", pcd)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## From open3d.PointCloud to NumPy\n",
    "As shown in this example, `pcd_load.points` of type `Vector3dVector` is converted into a NumPy array using `np.asarray`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Load saved point cloud and visualize it\n",
    "pcd_load = o3d.io.read_point_cloud(\"sync.ply\")\n",
    "\n",
    "# Convert Open3D.o3d.geometry.PointCloud to numpy array\n",
    "xyz_load = np.asarray(pcd_load.points)\n",
    "print('xyz_load')\n",
    "print(xyz_load)\n",
    "o3d.visualization.draw_geometries([pcd_load])"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Edit 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.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
