adapted from https://github.com/cduck/hyperbolic/blob/master/examples/poincare.ipynb
Last active
October 21, 2024 00:37
-
-
Save lucasw/a746150b986bea9337579263ea63ae6b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"id": "6de13e4d", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import math\n", | |
"import random\n", | |
"\n", | |
"import drawsvg as draw\n", | |
"from drawsvg import Drawing\n", | |
"from hyperbolic import euclid, util\n", | |
"from hyperbolic.poincare import *" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"id": "1258f18a", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def hyp_poly_edge_construct(p, q):\n", | |
" pi, pi2 = math.pi, math.pi*2\n", | |
" th = pi2/q\n", | |
" phi = pi2/p\n", | |
" ang1 = pi-phi/2-th/2-pi/2\n", | |
" ang2 = th/2 + pi/2\n", | |
" a = math.sin(ang2)/math.sin(ang1)\n", | |
" b = math.sin(phi/2)/math.sin(ang1)\n", | |
" r_p = math.sqrt(1/(a**2-b**2))\n", | |
" r_c = a*r_p\n", | |
" r_from_c = b*r_p\n", | |
" #return r_c, r_from_c\n", | |
" t1 = pi - math.asin(r_c / (r_from_c / math.sin(phi/2)))\n", | |
" t2 = pi - t1 - phi/2\n", | |
" r = math.sin(t2) * (r_from_c / math.sin(phi/2))\n", | |
" return r" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"id": "250f2d5a", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"p = 5\n", | |
"corner_deg = 90\n", | |
"q = 360 / corner_deg\n", | |
"skip = 1.0\n", | |
"r = hyp_poly_edge_construct(p, q)\n", | |
"p_list = [\n", | |
" Point.from_polar_euclid(r, deg=-skip*i*360/p)\n", | |
" for i in range(p)\n", | |
"]\n", | |
"print(p_list)\n", | |
"\n", | |
"n = len(p_list)\n", | |
"e_list = [Line.from_points(*p_list[i], *p_list[(i+1)%n]) for i in range(n)]\n", | |
"poly = Polygon(e_list, join=True)\n", | |
"\n", | |
"d = Drawing(2.1, 2.1, origin='center')\n", | |
"d.draw(euclid.Circle(0, 0, 1), fill='silver')\n", | |
"for edge in e_list:\n", | |
" d.draw(edge, hwidth=0.05, fill='blue')\n", | |
"# d.draw(poly, hwidth=(0,-0.15), fill='green')\n", | |
"# d.draw(poly, fill='black', opacity=0.3)\n", | |
"# for p in p_list:\n", | |
"# d.draw(p, radius=0.05, stroke_width=0.01, stroke='#ccccff',\n", | |
"# fill='none', opacity=0.6)\n", | |
"\n", | |
"d.set_render_size(w=400)\n", | |
"d.save_svg('images/polyRegular.svg')\n", | |
"d" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 225, | |
"id": "a16f9890", | |
"metadata": { | |
"scrolled": false | |
}, | |
"outputs": [], | |
"source": [ | |
"def construct_poly_vertices(p, q, deg_offset=0, skip=1):\n", | |
" r = hyp_poly_edge_construct(p, q)\n", | |
" return [\n", | |
" Point.from_polar_euclid(r, deg=-skip*i*360/p+deg_offset)\n", | |
" for i in range(p)\n", | |
" ]\n", | |
" \n", | |
"def construct_poly_from_points(pt_list):\n", | |
" p = len(p_list)\n", | |
" e_list = [Line.from_points(*pt_list[i], *pt_list[(i + 1) % p]) for i in range(p)]\n", | |
" return Polygon(e_list, join=True)\n", | |
"\n", | |
"def draw_poly(poly, color=\"#ffffff\"):\n", | |
" d.draw(poly, fill=color, opacity=0.25)\n", | |
" d.draw(poly, hwidth=(0.0,0.05), fill='blue')\n", | |
" \n", | |
"def draw_points(p_list):\n", | |
" for pt in p_list:\n", | |
" d.draw(pt, hradius=0.15, hwidth=0.02,\n", | |
" fill='white', opacity=0.9)\n", | |
"\n", | |
"for ind in range(50):\n", | |
" d = Drawing(2.1, 2.1, origin='center')\n", | |
" d.draw(euclid.Circle(0, 0, 1), fill='#f9f9f9')\n", | |
"\n", | |
" p = 5\n", | |
" q = 4\n", | |
" # print('Inner angle:', 360/q)\n", | |
"\n", | |
" # the central polygon\n", | |
" pt_list = construct_poly_vertices(p, q)\n", | |
" rot_trans = Transform.rotation(deg=270)\n", | |
" offset = Transform.translation(Point(-0.5 + ind * 0.025, -0.0))\n", | |
" trans = Transform.merge(offset, rot_trans)\n", | |
" pt_list = trans.apply_to_list(pt_list)\n", | |
" poly = Polygon.from_vertices(pt_list)\n", | |
" draw_poly(poly)\n", | |
"\n", | |
" def ring(p, q, i0, i1, pt_list):\n", | |
" pt_list2 = construct_poly_vertices(p, q)\n", | |
" t0 = pt_list2[0]\n", | |
" t1 = pt_list2[1]\n", | |
" trans_to_origin = Transform.shift_origin(t0, t1)\n", | |
" # print(f\"trans_to_origin: {t0} {t1} -> {trans_to_origin}\")\n", | |
" if False:\n", | |
" px, py = trans_to_origin.apply_to_tuple(p_list2[-1])\n", | |
" # print('Inner angle:', math.degrees(math.atan2(py,px)))\n", | |
"\n", | |
" poly_list = []\n", | |
" pt_list_list = []\n", | |
" for i in range(i0, i1):\n", | |
" t0 = pt_list[(i + 1) % p]\n", | |
" t1 = pt_list[i]\n", | |
" trans_to_side = Transform.translation(t0, t1)\n", | |
" # print(f\"{i} t: {tx} {ty} -> {trans_to_side}\")\n", | |
" # offset = Transform.rotation(deg=5)\n", | |
" # offset = Transform.translation(Point(0.1, 0.0))\n", | |
" offset = Transform.translation(Point(0.0, 0.0))\n", | |
" trans = Transform.merge(offset, trans_to_origin, trans_to_side)\n", | |
" pt_list2r = trans.apply_to_list(pt_list2)\n", | |
" poly2 = Polygon.from_vertices(pt_list2r)\n", | |
" pt_list_list.append(pt_list2r)\n", | |
" poly_list.append(poly2)\n", | |
"\n", | |
" for poly2 in poly_list:\n", | |
" draw_poly(poly2)\n", | |
" # draw_points(p_list)\n", | |
" # for pt_list2 in pt_list_list:\n", | |
" # draw_points(pt_list2)\n", | |
"\n", | |
" return poly_list, pt_list_list\n", | |
"\n", | |
" poly_list, pt_list_list = ring(p, q, i0=0, i1=p, pt_list=pt_list)\n", | |
"\n", | |
" # TODO(lucasw) need to avoid drawing the same shape twice\n", | |
" if True:\n", | |
" for poly, pt_list in zip(poly_list, pt_list_list):\n", | |
" poly_list, pt_list_list = ring(p, q, 1, 4, pt_list)\n", | |
" for poly, pt_list in zip(poly_list, pt_list_list):\n", | |
" poly_list, pt_list_list = ring(p, q, 0, 4, pt_list)\n", | |
" for poly, pt_list in zip(poly_list, pt_list_list):\n", | |
" poly_list, pt_list_list = ring(p, q, 0, 5, pt_list)\n", | |
" for poly, pt_list in zip(poly_list, pt_list_list):\n", | |
" poly_list, pt_list_list = ring(p, q, 0, 5, pt_list)\n", | |
"\n", | |
" d.set_render_size(w=1080)\n", | |
" name = f'images/poly_tile_{p}_{q}_{ind:05d}'\n", | |
" d.save_png(name + \".png\")\n", | |
" d" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "myenv", | |
"language": "python", | |
"name": "myenv" | |
}, | |
"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.12.3" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 5 | |
} |
Author
lucasw
commented
Oct 21, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment