{ "cells": [ { "cell_type": "markdown", "id": "97dbdadd-7a94-4939-8ed5-c8551b662917", "metadata": {}, "source": [ "# Circle Segment Intersection (for interpolation)\n", "Here is an interactive plot that demonstrates the functionality of the formula to calculate the intersection of a line segment, and a circle centered at the origin." ] }, { "cell_type": "code", "execution_count": 8, "id": "d31dc723-a6dc-400d-8b31-fe84ea6d5e45", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "cbfad4e8309a4ee2bef53994add83330", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(Label(value='A and B can be moved with the mouse. One must be inside the circle, and one must b…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from bqplot import *\n", "import numpy as np\n", "import ipywidgets as widgets\n", "\n", "\n", "def circle_segment_intersection(p1, p2, r):\n", " x1, y1 = p1\n", " x2, y2 = p2\n", " dx = x2 - x1\n", " dy = y2 - y1\n", " dr2 = dx ** 2 + dy ** 2\n", " D = x1 * y2 - x2 * y1\n", " d1 = x1 ** 2 + y1 ** 2\n", " d2 = x2 ** 2 + y2 ** 2\n", " dd = d2 - d1\n", " sqrt_term = np.sqrt(r ** 2 * dr2 - D ** 2)\n", " x = (D * dy + np.copysign(1.0, dd) * dx * sqrt_term) / dr2\n", " y = (-D * dx + np.copysign(1.0, dd) * dy * sqrt_term) / dr2\n", " return x, y\n", "\n", "\n", "MAX = 5.0\n", "x_sc = LinearScale(min=-MAX, max=MAX)\n", "y_sc = LinearScale(min=-MAX, max=MAX)\n", "\n", "ax_x = Axis(label=\"x\", scale=x_sc, tick_format=\"0.0f\")\n", "ax_y = Axis(label=\"y\", scale=y_sc, orientation=\"vertical\", tick_format=\"0.0f\")\n", "\n", "points = Scatter(\n", " names=[\"A\", \"B\"], x=[0.0, 3.0], y=[2.0, 4.0], scales={\"x\": x_sc, \"y\": y_sc}, enable_move=True\n", ")\n", "\n", "\n", "def get_circle(r):\n", " t = np.linspace(0, 2 * np.pi)\n", " x = r * np.cos(t)\n", " y = r * np.sin(t)\n", " return x, y\n", "\n", "radius_slider = widgets.FloatSlider(min=0.0, max=MAX, value=3.0, description=\"Circle radius\")\n", "circle_x, circle_y = get_circle(radius_slider.value)\n", "\n", "circle = Lines(x=circle_x, y=circle_y, scales={\"x\": x_sc, \"y\": y_sc}, colors=[\"green\"])\n", "\n", "x1, x2 = points.x\n", "y1, y2 = points.y\n", "xi, yi = circle_segment_intersection((x1, y1), (x2, y2), radius_slider.value)\n", "\n", "intersection = Scatter(\n", " names=[\"C\"],\n", " x=[xi],\n", " y=[yi],\n", " scales={\"x\": x_sc, \"y\": y_sc},\n", " enable_move=False,\n", " colors=[\"purple\"],\n", ")\n", "\n", "fig = Figure(axes=[ax_x, ax_y], marks=[circle, points, intersection])\n", "\n", "fig.max_aspect_ratio = 1\n", "fig.min_aspect_ratio = 1\n", "\n", "\n", "def both_inside_or_both_outside_circle(points, r):\n", " x1, x2 = points.x\n", " y1, y2 = points.y\n", " d1 = x1 ** 2 + y1 ** 2\n", " d2 = x2 ** 2 + y2 ** 2\n", " if d1 < r ** 2 and d2 < r ** 2:\n", " return True\n", " elif d1 > r ** 2 and d2 > r ** 2:\n", " return True\n", " else:\n", " return False\n", "\n", "\n", "def update_circle(message):\n", " circle_x, circle_y = get_circle(radius_slider.value)\n", " circle.x = circle_x\n", " circle.y = circle_y\n", " update_intersection(message)\n", "\n", "\n", "def update_intersection(message):\n", " x1, x2 = points.x\n", " y1, y2 = points.y\n", " r = radius_slider.value\n", " if both_inside_or_both_outside_circle(points, r):\n", " circle.colors = [\"red\"]\n", " intersection.x = []\n", " intersection.y = []\n", " else:\n", " circle.colors = [\"green\"]\n", " xi, yi = circle_segment_intersection((x1, y1), (x2, y2), r)\n", " intersection.x = [xi]\n", " intersection.y = [yi]\n", "\n", "\n", "points.observe(update_intersection, [\"x\", \"y\"])\n", "\n", "radius_slider.observe(update_circle, \"value\")\n", "\n", "widgets.VBox(\n", " [\n", " widgets.Label(\n", " \"A and B can be moved with the mouse. One must be inside the circle, and one must be outside.\",\n", " fixed=True,\n", " ),\n", " radius_slider,\n", " fig,\n", " ]\n", ")" ] } ], "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": 5 }