{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "A demonstration of mesh-plane cross-sections, commonly referred to\n",
    "as \"slicing\" in the context of 3D printing.\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from shapely.geometry import LineString\n",
    "\n",
    "import trimesh\n",
    "\n",
    "%pylab inline\n",
    "%config InlineBackend.figure_format = 'svg'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# load the mesh from filename\n",
    "# file objects are also supported\n",
    "mesh = trimesh.load_mesh(\"../models/featuretype.STL\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# get a single cross section of the mesh\n",
    "slice = mesh.section(plane_origin=mesh.centroid, plane_normal=[0, 0, 1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# the section will be in the original mesh frame\n",
    "slice.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# we can move the 3D curve to a Path2D object easily\n",
    "slice_2D, to_3D = slice.to_planar()\n",
    "slice_2D.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# if we wanted to take a bunch of parallel slices, like for a 3D printer\n",
    "# we can do that easily with the section_multiplane method\n",
    "# we're going to slice the mesh into evenly spaced chunks along z\n",
    "# this takes the (2,3) bounding box and slices it into [minz, maxz]\n",
    "z_extents = mesh.bounds[:, 2]\n",
    "# slice every .125 model units (eg, inches)\n",
    "z_levels = np.arange(*z_extents, step=0.125)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# find a bunch of parallel cross sections\n",
    "sections = mesh.section_multiplane(\n",
    "    plane_origin=mesh.bounds[0], plane_normal=[0, 0, 1], heights=z_levels\n",
    ")\n",
    "sections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# summing the array of Path2D objects will put all of the curves\n",
    "# into one Path2D object, which we can plot easily\n",
    "combined = np.sum(sections)\n",
    "combined.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# if we want to intersect a line with this 2D polygon, we can use shapely methods\n",
    "polygon = slice_2D.polygons_full[0]\n",
    "# intersect line with one of the polygons\n",
    "hits = polygon.intersection(LineString([[-4, -1], [3, 0]]))\n",
    "# check what class the intersection returned\n",
    "hits.__class__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# we can plot the intersection (red) and our original geometry(black and green)\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "ax = plt.gca()\n",
    "for h in hits.geoms:\n",
    "    ax.plot(*h.xy, color=\"r\")\n",
    "slice_2D.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# the medial axis is available for closed Path2D objects\n",
    "(slice_2D + slice_2D.medial_axis()).show()"
   ]
  }
 ],
 "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.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
