snappy 3.2__cp313-cp313-macosx_11_0_arm64.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (503) hide show
  1. snappy/CyOpenGL.cpython-313-darwin.so +0 -0
  2. snappy/SnapPy.cpython-313-darwin.so +0 -0
  3. snappy/SnapPy.ico +0 -0
  4. snappy/SnapPy.png +0 -0
  5. snappy/SnapPyHP.cpython-313-darwin.so +0 -0
  6. snappy/__init__.py +760 -0
  7. snappy/app.py +605 -0
  8. snappy/app_menus.py +372 -0
  9. snappy/browser.py +998 -0
  10. snappy/cache.py +25 -0
  11. snappy/canonical.py +249 -0
  12. snappy/cusps/__init__.py +38 -0
  13. snappy/cusps/cusp_area_matrix.py +101 -0
  14. snappy/cusps/cusp_areas_from_matrix.py +173 -0
  15. snappy/cusps/maximal_cusp_area_matrix.py +136 -0
  16. snappy/cusps/test.py +21 -0
  17. snappy/cusps/trig_cusp_area_matrix.py +63 -0
  18. snappy/database.py +454 -0
  19. snappy/db_utilities.py +79 -0
  20. snappy/decorated_isosig.py +710 -0
  21. snappy/dev/__init__.py +0 -0
  22. snappy/dev/extended_ptolemy/__init__.py +8 -0
  23. snappy/dev/extended_ptolemy/closed.py +106 -0
  24. snappy/dev/extended_ptolemy/complexVolumesClosed.py +149 -0
  25. snappy/dev/extended_ptolemy/direct.py +42 -0
  26. snappy/dev/extended_ptolemy/extended.py +406 -0
  27. snappy/dev/extended_ptolemy/giac_helper.py +43 -0
  28. snappy/dev/extended_ptolemy/giac_rur.py +129 -0
  29. snappy/dev/extended_ptolemy/gluing.py +46 -0
  30. snappy/dev/extended_ptolemy/phc_wrapper.py +220 -0
  31. snappy/dev/extended_ptolemy/printMatrices.py +70 -0
  32. snappy/dev/vericlosed/__init__.py +1 -0
  33. snappy/dev/vericlosed/computeApproxHyperbolicStructureNew.py +159 -0
  34. snappy/dev/vericlosed/computeApproxHyperbolicStructureOrb.py +90 -0
  35. snappy/dev/vericlosed/computeVerifiedHyperbolicStructure.py +111 -0
  36. snappy/dev/vericlosed/gimbalLoopFinder.py +130 -0
  37. snappy/dev/vericlosed/hyperbolicStructure.py +313 -0
  38. snappy/dev/vericlosed/krawczykCertifiedEdgeLengthsEngine.py +165 -0
  39. snappy/dev/vericlosed/oneVertexTruncatedComplex.py +122 -0
  40. snappy/dev/vericlosed/orb/__init__.py +1 -0
  41. snappy/dev/vericlosed/orb/orb_solution_for_snappea_finite_triangulation_mac +0 -0
  42. snappy/dev/vericlosed/parseVertexGramMatrixFile.py +47 -0
  43. snappy/dev/vericlosed/polishApproxHyperbolicStructure.py +61 -0
  44. snappy/dev/vericlosed/test.py +54 -0
  45. snappy/dev/vericlosed/truncatedComplex.py +176 -0
  46. snappy/dev/vericlosed/verificationError.py +58 -0
  47. snappy/dev/vericlosed/verifyHyperbolicStructureEngine.py +177 -0
  48. snappy/doc/_images/SnapPy-196.png +0 -0
  49. snappy/doc/_images/geodesics.jpg +0 -0
  50. snappy/doc/_images/m004_paper_plane_on_systole.jpg +0 -0
  51. snappy/doc/_images/m125_paper_plane.jpg +0 -0
  52. snappy/doc/_images/mac.png +0 -0
  53. snappy/doc/_images/o9_00000_systole_paper_plane.jpg +0 -0
  54. snappy/doc/_images/o9_00000_systole_paper_plane_closer.jpg +0 -0
  55. snappy/doc/_images/plink-action.png +0 -0
  56. snappy/doc/_images/ubuntu.png +0 -0
  57. snappy/doc/_images/win7.png +0 -0
  58. snappy/doc/_sources/additional_classes.rst.txt +40 -0
  59. snappy/doc/_sources/bugs.rst.txt +14 -0
  60. snappy/doc/_sources/censuses.rst.txt +51 -0
  61. snappy/doc/_sources/credits.rst.txt +75 -0
  62. snappy/doc/_sources/development.rst.txt +259 -0
  63. snappy/doc/_sources/index.rst.txt +182 -0
  64. snappy/doc/_sources/installing.rst.txt +247 -0
  65. snappy/doc/_sources/manifold.rst.txt +6 -0
  66. snappy/doc/_sources/manifoldhp.rst.txt +46 -0
  67. snappy/doc/_sources/news.rst.txt +355 -0
  68. snappy/doc/_sources/other.rst.txt +25 -0
  69. snappy/doc/_sources/platonic_census.rst.txt +20 -0
  70. snappy/doc/_sources/plink.rst.txt +102 -0
  71. snappy/doc/_sources/ptolemy.rst.txt +66 -0
  72. snappy/doc/_sources/ptolemy_classes.rst.txt +42 -0
  73. snappy/doc/_sources/ptolemy_examples1.rst.txt +298 -0
  74. snappy/doc/_sources/ptolemy_examples2.rst.txt +363 -0
  75. snappy/doc/_sources/ptolemy_examples3.rst.txt +301 -0
  76. snappy/doc/_sources/ptolemy_examples4.rst.txt +61 -0
  77. snappy/doc/_sources/ptolemy_prelim.rst.txt +105 -0
  78. snappy/doc/_sources/screenshots.rst.txt +21 -0
  79. snappy/doc/_sources/snap.rst.txt +87 -0
  80. snappy/doc/_sources/snappy.rst.txt +28 -0
  81. snappy/doc/_sources/spherogram.rst.txt +103 -0
  82. snappy/doc/_sources/todo.rst.txt +47 -0
  83. snappy/doc/_sources/triangulation.rst.txt +11 -0
  84. snappy/doc/_sources/tutorial.rst.txt +49 -0
  85. snappy/doc/_sources/verify.rst.txt +210 -0
  86. snappy/doc/_sources/verify_internals.rst.txt +79 -0
  87. snappy/doc/_static/SnapPy-horizontal-128.png +0 -0
  88. snappy/doc/_static/SnapPy.ico +0 -0
  89. snappy/doc/_static/_sphinx_javascript_frameworks_compat.js +123 -0
  90. snappy/doc/_static/basic.css +925 -0
  91. snappy/doc/_static/css/badge_only.css +1 -0
  92. snappy/doc/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
  93. snappy/doc/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
  94. snappy/doc/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
  95. snappy/doc/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
  96. snappy/doc/_static/css/fonts/fontawesome-webfont.eot +0 -0
  97. snappy/doc/_static/css/fonts/fontawesome-webfont.svg +2671 -0
  98. snappy/doc/_static/css/fonts/fontawesome-webfont.ttf +0 -0
  99. snappy/doc/_static/css/fonts/fontawesome-webfont.woff +0 -0
  100. snappy/doc/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
  101. snappy/doc/_static/css/fonts/lato-bold-italic.woff +0 -0
  102. snappy/doc/_static/css/fonts/lato-bold-italic.woff2 +0 -0
  103. snappy/doc/_static/css/fonts/lato-bold.woff +0 -0
  104. snappy/doc/_static/css/fonts/lato-bold.woff2 +0 -0
  105. snappy/doc/_static/css/fonts/lato-normal-italic.woff +0 -0
  106. snappy/doc/_static/css/fonts/lato-normal-italic.woff2 +0 -0
  107. snappy/doc/_static/css/fonts/lato-normal.woff +0 -0
  108. snappy/doc/_static/css/fonts/lato-normal.woff2 +0 -0
  109. snappy/doc/_static/css/theme.css +4 -0
  110. snappy/doc/_static/doctools.js +156 -0
  111. snappy/doc/_static/documentation_options.js +13 -0
  112. snappy/doc/_static/file.png +0 -0
  113. snappy/doc/_static/fonts/Lato/lato-bold.eot +0 -0
  114. snappy/doc/_static/fonts/Lato/lato-bold.ttf +0 -0
  115. snappy/doc/_static/fonts/Lato/lato-bold.woff +0 -0
  116. snappy/doc/_static/fonts/Lato/lato-bold.woff2 +0 -0
  117. snappy/doc/_static/fonts/Lato/lato-bolditalic.eot +0 -0
  118. snappy/doc/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
  119. snappy/doc/_static/fonts/Lato/lato-bolditalic.woff +0 -0
  120. snappy/doc/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
  121. snappy/doc/_static/fonts/Lato/lato-italic.eot +0 -0
  122. snappy/doc/_static/fonts/Lato/lato-italic.ttf +0 -0
  123. snappy/doc/_static/fonts/Lato/lato-italic.woff +0 -0
  124. snappy/doc/_static/fonts/Lato/lato-italic.woff2 +0 -0
  125. snappy/doc/_static/fonts/Lato/lato-regular.eot +0 -0
  126. snappy/doc/_static/fonts/Lato/lato-regular.ttf +0 -0
  127. snappy/doc/_static/fonts/Lato/lato-regular.woff +0 -0
  128. snappy/doc/_static/fonts/Lato/lato-regular.woff2 +0 -0
  129. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
  130. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
  131. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
  132. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
  133. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
  134. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
  135. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
  136. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
  137. snappy/doc/_static/jquery.js +2 -0
  138. snappy/doc/_static/js/badge_only.js +1 -0
  139. snappy/doc/_static/js/theme.js +1 -0
  140. snappy/doc/_static/js/versions.js +228 -0
  141. snappy/doc/_static/language_data.js +199 -0
  142. snappy/doc/_static/minus.png +0 -0
  143. snappy/doc/_static/plus.png +0 -0
  144. snappy/doc/_static/pygments.css +75 -0
  145. snappy/doc/_static/searchtools.js +620 -0
  146. snappy/doc/_static/snappy_furo.css +33 -0
  147. snappy/doc/_static/snappy_sphinx_rtd_theme.css +42 -0
  148. snappy/doc/_static/sphinx_highlight.js +154 -0
  149. snappy/doc/additional_classes.html +1500 -0
  150. snappy/doc/bugs.html +132 -0
  151. snappy/doc/censuses.html +427 -0
  152. snappy/doc/credits.html +181 -0
  153. snappy/doc/development.html +384 -0
  154. snappy/doc/genindex.html +1331 -0
  155. snappy/doc/index.html +262 -0
  156. snappy/doc/installing.html +346 -0
  157. snappy/doc/manifold.html +3452 -0
  158. snappy/doc/manifoldhp.html +180 -0
  159. snappy/doc/news.html +388 -0
  160. snappy/doc/objects.inv +0 -0
  161. snappy/doc/other.html +161 -0
  162. snappy/doc/platonic_census.html +375 -0
  163. snappy/doc/plink.html +210 -0
  164. snappy/doc/ptolemy.html +254 -0
  165. snappy/doc/ptolemy_classes.html +1144 -0
  166. snappy/doc/ptolemy_examples1.html +409 -0
  167. snappy/doc/ptolemy_examples2.html +471 -0
  168. snappy/doc/ptolemy_examples3.html +414 -0
  169. snappy/doc/ptolemy_examples4.html +195 -0
  170. snappy/doc/ptolemy_prelim.html +248 -0
  171. snappy/doc/py-modindex.html +165 -0
  172. snappy/doc/screenshots.html +141 -0
  173. snappy/doc/search.html +135 -0
  174. snappy/doc/searchindex.js +1 -0
  175. snappy/doc/snap.html +202 -0
  176. snappy/doc/snappy.html +181 -0
  177. snappy/doc/spherogram.html +1211 -0
  178. snappy/doc/todo.html +166 -0
  179. snappy/doc/triangulation.html +1584 -0
  180. snappy/doc/tutorial.html +159 -0
  181. snappy/doc/verify.html +330 -0
  182. snappy/doc/verify_internals.html +1235 -0
  183. snappy/drilling/__init__.py +456 -0
  184. snappy/drilling/barycentric.py +103 -0
  185. snappy/drilling/constants.py +5 -0
  186. snappy/drilling/crush.py +270 -0
  187. snappy/drilling/cusps.py +125 -0
  188. snappy/drilling/debug.py +242 -0
  189. snappy/drilling/epsilons.py +6 -0
  190. snappy/drilling/exceptions.py +55 -0
  191. snappy/drilling/moves.py +620 -0
  192. snappy/drilling/peripheral_curves.py +210 -0
  193. snappy/drilling/perturb.py +188 -0
  194. snappy/drilling/shorten.py +36 -0
  195. snappy/drilling/subdivide.py +274 -0
  196. snappy/drilling/test.py +23 -0
  197. snappy/drilling/test_cases.py +126 -0
  198. snappy/drilling/tracing.py +351 -0
  199. snappy/exceptions.py +26 -0
  200. snappy/export_stl.py +120 -0
  201. snappy/exterior_to_link/__init__.py +2 -0
  202. snappy/exterior_to_link/barycentric_geometry.py +463 -0
  203. snappy/exterior_to_link/exceptions.py +6 -0
  204. snappy/exterior_to_link/geodesic_map.json +14408 -0
  205. snappy/exterior_to_link/hyp_utils.py +112 -0
  206. snappy/exterior_to_link/link_projection.py +323 -0
  207. snappy/exterior_to_link/main.py +197 -0
  208. snappy/exterior_to_link/mcomplex_with_expansion.py +261 -0
  209. snappy/exterior_to_link/mcomplex_with_link.py +687 -0
  210. snappy/exterior_to_link/mcomplex_with_memory.py +162 -0
  211. snappy/exterior_to_link/pl_utils.py +491 -0
  212. snappy/exterior_to_link/put_in_S3.py +156 -0
  213. snappy/exterior_to_link/rational_linear_algebra.py +123 -0
  214. snappy/exterior_to_link/rational_linear_algebra_wrapped.py +135 -0
  215. snappy/exterior_to_link/simplify_to_base_tri.py +114 -0
  216. snappy/exterior_to_link/stored_moves.py +475 -0
  217. snappy/exterior_to_link/test.py +31 -0
  218. snappy/filedialog.py +28 -0
  219. snappy/geometric_structure/__init__.py +212 -0
  220. snappy/geometric_structure/cusp_neighborhood/__init__.py +3 -0
  221. snappy/geometric_structure/cusp_neighborhood/complex_cusp_cross_section.py +697 -0
  222. snappy/geometric_structure/cusp_neighborhood/cusp_cross_section_base.py +484 -0
  223. snappy/geometric_structure/cusp_neighborhood/exceptions.py +42 -0
  224. snappy/geometric_structure/cusp_neighborhood/real_cusp_cross_section.py +298 -0
  225. snappy/geometric_structure/cusp_neighborhood/tiles_for_cusp_neighborhood.py +159 -0
  226. snappy/geometric_structure/cusp_neighborhood/vertices.py +32 -0
  227. snappy/geometric_structure/geodesic/__init__.py +0 -0
  228. snappy/geometric_structure/geodesic/add_core_curves.py +152 -0
  229. snappy/geometric_structure/geodesic/avoid_core_curves.py +369 -0
  230. snappy/geometric_structure/geodesic/canonical_keys.py +52 -0
  231. snappy/geometric_structure/geodesic/check_away_from_core_curve.py +60 -0
  232. snappy/geometric_structure/geodesic/constants.py +6 -0
  233. snappy/geometric_structure/geodesic/exceptions.py +22 -0
  234. snappy/geometric_structure/geodesic/fixed_points.py +93 -0
  235. snappy/geometric_structure/geodesic/geodesic_start_point_info.py +435 -0
  236. snappy/geometric_structure/geodesic/graph_trace_helper.py +67 -0
  237. snappy/geometric_structure/geodesic/line.py +30 -0
  238. snappy/geometric_structure/geodesic/multiplicity.py +127 -0
  239. snappy/geometric_structure/geodesic/tiles_for_geodesic.py +101 -0
  240. snappy/geometric_structure/test.py +22 -0
  241. snappy/gui.py +121 -0
  242. snappy/horoviewer.py +443 -0
  243. snappy/hyperboloid/__init__.py +212 -0
  244. snappy/hyperboloid/distances.py +245 -0
  245. snappy/hyperboloid/horoball.py +19 -0
  246. snappy/hyperboloid/line.py +35 -0
  247. snappy/hyperboloid/point.py +9 -0
  248. snappy/hyperboloid/triangle.py +29 -0
  249. snappy/info_icon.gif +0 -0
  250. snappy/infowindow.py +65 -0
  251. snappy/isometry_signature.py +382 -0
  252. snappy/len_spec/__init__.py +596 -0
  253. snappy/len_spec/geodesic_info.py +110 -0
  254. snappy/len_spec/geodesic_key_info_dict.py +117 -0
  255. snappy/len_spec/geodesic_piece.py +143 -0
  256. snappy/len_spec/geometric_structure.py +182 -0
  257. snappy/len_spec/geometry.py +80 -0
  258. snappy/len_spec/length_spectrum_geodesic_info.py +170 -0
  259. snappy/len_spec/spine.py +206 -0
  260. snappy/len_spec/test.py +24 -0
  261. snappy/len_spec/test_cases.py +69 -0
  262. snappy/len_spec/tile.py +275 -0
  263. snappy/len_spec/word.py +86 -0
  264. snappy/manifolds/HTWKnots/alternating.gz +0 -0
  265. snappy/manifolds/HTWKnots/nonalternating.gz +0 -0
  266. snappy/manifolds/__init__.py +3 -0
  267. snappy/math_basics.py +176 -0
  268. snappy/matrix.py +525 -0
  269. snappy/number.py +657 -0
  270. snappy/numeric_output_checker.py +345 -0
  271. snappy/pari.py +41 -0
  272. snappy/phone_home.py +57 -0
  273. snappy/polyviewer.py +259 -0
  274. snappy/ptolemy/__init__.py +17 -0
  275. snappy/ptolemy/component.py +103 -0
  276. snappy/ptolemy/coordinates.py +2290 -0
  277. snappy/ptolemy/fieldExtensions.py +153 -0
  278. snappy/ptolemy/findLoops.py +473 -0
  279. snappy/ptolemy/geometricRep.py +59 -0
  280. snappy/ptolemy/homology.py +165 -0
  281. snappy/ptolemy/magma/default.magma_template +229 -0
  282. snappy/ptolemy/magma/radicalsOfPrimaryDecomposition.magma_template +79 -0
  283. snappy/ptolemy/manifoldMethods.py +395 -0
  284. snappy/ptolemy/matrix.py +350 -0
  285. snappy/ptolemy/numericalSolutionsToGroebnerBasis.py +113 -0
  286. snappy/ptolemy/polynomial.py +857 -0
  287. snappy/ptolemy/processComponents.py +173 -0
  288. snappy/ptolemy/processFileBase.py +247 -0
  289. snappy/ptolemy/processFileDispatch.py +46 -0
  290. snappy/ptolemy/processMagmaFile.py +392 -0
  291. snappy/ptolemy/processRurFile.py +150 -0
  292. snappy/ptolemy/ptolemyGeneralizedObstructionClass.py +102 -0
  293. snappy/ptolemy/ptolemyObstructionClass.py +64 -0
  294. snappy/ptolemy/ptolemyVariety.py +1029 -0
  295. snappy/ptolemy/ptolemyVarietyPrimeIdealGroebnerBasis.py +140 -0
  296. snappy/ptolemy/reginaWrapper.py +698 -0
  297. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c0.magma_out.bz2 +0 -0
  298. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c1.magma_out.bz2 +0 -0
  299. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c2.magma_out.bz2 +0 -0
  300. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c3.magma_out.bz2 +0 -0
  301. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c4.magma_out.bz2 +0 -0
  302. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c5.magma_out.bz2 +0 -0
  303. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c6.magma_out.bz2 +0 -0
  304. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c7.magma_out.bz2 +0 -0
  305. snappy/ptolemy/regina_testing_files_generalized/m003__sl3_c0.magma_out.bz2 +0 -0
  306. snappy/ptolemy/regina_testing_files_generalized/m003__sl3_c1.magma_out.bz2 +0 -0
  307. snappy/ptolemy/regina_testing_files_generalized/m015__sl2_c0.magma_out.bz2 +0 -0
  308. snappy/ptolemy/regina_testing_files_generalized/m015__sl2_c1.magma_out.bz2 +0 -0
  309. snappy/ptolemy/regina_testing_files_generalized/m015__sl3_c0.magma_out.bz2 +0 -0
  310. snappy/ptolemy/regina_testing_files_generalized/m015__sl3_c1.magma_out.bz2 +0 -0
  311. snappy/ptolemy/rur.py +545 -0
  312. snappy/ptolemy/solutionsToPrimeIdealGroebnerBasis.py +277 -0
  313. snappy/ptolemy/test.py +1126 -0
  314. snappy/ptolemy/testing_files/3_1__sl2_c0.magma_out.bz2 +0 -0
  315. snappy/ptolemy/testing_files/3_1__sl2_c1.magma_out.bz2 +0 -0
  316. snappy/ptolemy/testing_files/4_1__sl2_c0.magma_out.bz2 +0 -0
  317. snappy/ptolemy/testing_files/4_1__sl2_c1.magma_out.bz2 +0 -0
  318. snappy/ptolemy/testing_files/4_1__sl3_c0.magma_out.bz2 +0 -0
  319. snappy/ptolemy/testing_files/4_1__sl4_c0.magma_out.bz2 +0 -0
  320. snappy/ptolemy/testing_files/4_1__sl4_c1.magma_out.bz2 +0 -0
  321. snappy/ptolemy/testing_files/5_2__sl2_c0.magma_out.bz2 +0 -0
  322. snappy/ptolemy/testing_files/5_2__sl2_c1.magma_out.bz2 +0 -0
  323. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c0.magma_out.bz2 +0 -0
  324. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c1.magma_out.bz2 +0 -0
  325. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c2.magma_out.bz2 +0 -0
  326. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c3.magma_out.bz2 +0 -0
  327. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c4.magma_out.bz2 +0 -0
  328. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c5.magma_out.bz2 +0 -0
  329. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c6.magma_out.bz2 +0 -0
  330. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c7.magma_out.bz2 +0 -0
  331. snappy/ptolemy/testing_files/data/pgl2/OrientableCuspedCensus/03_tetrahedra/m019__sl2_c0.magma_out +95 -0
  332. snappy/ptolemy/testing_files/data/pgl2/OrientableCuspedCensus/03_tetrahedra/m019__sl2_c1.magma_out +95 -0
  333. snappy/ptolemy/testing_files/m015__sl3_c0.magma_out.bz2 +0 -0
  334. snappy/ptolemy/testing_files/m135__sl2_c0.magma_out.bz2 +0 -0
  335. snappy/ptolemy/testing_files/m135__sl2_c1.magma_out.bz2 +0 -0
  336. snappy/ptolemy/testing_files/m135__sl2_c2.magma_out.bz2 +0 -0
  337. snappy/ptolemy/testing_files/m135__sl2_c3.magma_out.bz2 +0 -0
  338. snappy/ptolemy/testing_files/m135__sl2_c4.magma_out.bz2 +0 -0
  339. snappy/ptolemy/testing_files/m135__sl2_c5.magma_out.bz2 +0 -0
  340. snappy/ptolemy/testing_files/m135__sl2_c6.magma_out.bz2 +0 -0
  341. snappy/ptolemy/testing_files/m135__sl2_c7.magma_out.bz2 +0 -0
  342. snappy/ptolemy/testing_files/s000__sl2_c0.magma_out.bz2 +0 -0
  343. snappy/ptolemy/testing_files/s000__sl2_c1.magma_out.bz2 +0 -0
  344. snappy/ptolemy/testing_files/t00000__sl2_c0.magma_out.bz2 +0 -0
  345. snappy/ptolemy/testing_files/t00000__sl2_c1.magma_out.bz2 +0 -0
  346. snappy/ptolemy/testing_files/v0000__sl2_c0.magma_out.bz2 +0 -0
  347. snappy/ptolemy/testing_files/v0000__sl2_c1.magma_out.bz2 +0 -0
  348. snappy/ptolemy/testing_files/v0000__sl2_c2.magma_out.bz2 +0 -0
  349. snappy/ptolemy/testing_files/v0000__sl2_c3.magma_out.bz2 +0 -0
  350. snappy/ptolemy/testing_files_generalized/m003__sl2_c0.magma_out.bz2 +0 -0
  351. snappy/ptolemy/testing_files_generalized/m003__sl2_c1.magma_out.bz2 +0 -0
  352. snappy/ptolemy/testing_files_generalized/m003__sl3_c0.magma_out.bz2 +0 -0
  353. snappy/ptolemy/testing_files_generalized/m003__sl3_c1.magma_out.bz2 +0 -0
  354. snappy/ptolemy/testing_files_generalized/m004__sl2_c0.magma_out.bz2 +0 -0
  355. snappy/ptolemy/testing_files_generalized/m004__sl2_c1.magma_out.bz2 +0 -0
  356. snappy/ptolemy/testing_files_generalized/m015__sl2_c1.magma_out.bz2 +0 -0
  357. snappy/ptolemy/testing_files_generalized/m015__sl3_c0.magma_out.bz2 +0 -0
  358. snappy/ptolemy/testing_files_rur/m052__sl3_c0.rur.bz2 +0 -0
  359. snappy/ptolemy/utilities.py +236 -0
  360. snappy/raytracing/__init__.py +64 -0
  361. snappy/raytracing/additional_horospheres.py +64 -0
  362. snappy/raytracing/additional_len_spec_choices.py +63 -0
  363. snappy/raytracing/cohomology_fractal.py +197 -0
  364. snappy/raytracing/eyeball.py +123 -0
  365. snappy/raytracing/finite_raytracing_data.py +237 -0
  366. snappy/raytracing/finite_viewer.py +590 -0
  367. snappy/raytracing/geodesic_tube_info.py +174 -0
  368. snappy/raytracing/geodesics.py +246 -0
  369. snappy/raytracing/geodesics_window.py +258 -0
  370. snappy/raytracing/gui_utilities.py +293 -0
  371. snappy/raytracing/hyperboloid_navigation.py +556 -0
  372. snappy/raytracing/hyperboloid_utilities.py +234 -0
  373. snappy/raytracing/ideal_raytracing_data.py +592 -0
  374. snappy/raytracing/inside_viewer.py +974 -0
  375. snappy/raytracing/pack.py +22 -0
  376. snappy/raytracing/raytracing_data.py +126 -0
  377. snappy/raytracing/raytracing_view.py +454 -0
  378. snappy/raytracing/shaders/Eye.png +0 -0
  379. snappy/raytracing/shaders/NonGeometric.png +0 -0
  380. snappy/raytracing/shaders/__init__.py +101 -0
  381. snappy/raytracing/shaders/fragment.glsl +1744 -0
  382. snappy/raytracing/test.py +29 -0
  383. snappy/raytracing/tooltip.py +146 -0
  384. snappy/raytracing/upper_halfspace_utilities.py +98 -0
  385. snappy/raytracing/view_scale_controller.py +98 -0
  386. snappy/raytracing/zoom_slider/__init__.py +263 -0
  387. snappy/raytracing/zoom_slider/inward.png +0 -0
  388. snappy/raytracing/zoom_slider/inward18.png +0 -0
  389. snappy/raytracing/zoom_slider/outward.png +0 -0
  390. snappy/raytracing/zoom_slider/outward18.png +0 -0
  391. snappy/raytracing/zoom_slider/test.py +20 -0
  392. snappy/sage_helper.py +117 -0
  393. snappy/settings.py +409 -0
  394. snappy/shell.py +53 -0
  395. snappy/snap/__init__.py +114 -0
  396. snappy/snap/character_varieties.py +375 -0
  397. snappy/snap/find_field.py +372 -0
  398. snappy/snap/fundamental_polyhedron.py +569 -0
  399. snappy/snap/generators.py +39 -0
  400. snappy/snap/interval_reps.py +81 -0
  401. snappy/snap/kernel_structures.py +128 -0
  402. snappy/snap/mcomplex_base.py +18 -0
  403. snappy/snap/nsagetools.py +702 -0
  404. snappy/snap/peripheral/__init__.py +1 -0
  405. snappy/snap/peripheral/dual_cellulation.py +219 -0
  406. snappy/snap/peripheral/link.py +127 -0
  407. snappy/snap/peripheral/peripheral.py +159 -0
  408. snappy/snap/peripheral/surface.py +522 -0
  409. snappy/snap/peripheral/test.py +35 -0
  410. snappy/snap/polished_reps.py +335 -0
  411. snappy/snap/shapes.py +152 -0
  412. snappy/snap/slice_obs_HKL.py +668 -0
  413. snappy/snap/t3mlite/__init__.py +2 -0
  414. snappy/snap/t3mlite/arrow.py +243 -0
  415. snappy/snap/t3mlite/corner.py +22 -0
  416. snappy/snap/t3mlite/edge.py +172 -0
  417. snappy/snap/t3mlite/face.py +37 -0
  418. snappy/snap/t3mlite/files.py +211 -0
  419. snappy/snap/t3mlite/homology.py +53 -0
  420. snappy/snap/t3mlite/linalg.py +419 -0
  421. snappy/snap/t3mlite/mcomplex.py +1499 -0
  422. snappy/snap/t3mlite/perm4.py +320 -0
  423. snappy/snap/t3mlite/setup.py +12 -0
  424. snappy/snap/t3mlite/simplex.py +199 -0
  425. snappy/snap/t3mlite/spun.py +297 -0
  426. snappy/snap/t3mlite/surface.py +519 -0
  427. snappy/snap/t3mlite/test.py +20 -0
  428. snappy/snap/t3mlite/test_vs_regina.py +86 -0
  429. snappy/snap/t3mlite/tetrahedron.py +109 -0
  430. snappy/snap/t3mlite/vertex.py +42 -0
  431. snappy/snap/test.py +134 -0
  432. snappy/snap/utilities.py +288 -0
  433. snappy/test.py +209 -0
  434. snappy/test_cases.py +263 -0
  435. snappy/testing.py +131 -0
  436. snappy/tiling/__init__.py +2 -0
  437. snappy/tiling/canonical_key_dict.py +59 -0
  438. snappy/tiling/dict_based_set.py +79 -0
  439. snappy/tiling/floor.py +49 -0
  440. snappy/tiling/hyperboloid_dict.py +54 -0
  441. snappy/tiling/iter_utils.py +78 -0
  442. snappy/tiling/lifted_tetrahedron.py +22 -0
  443. snappy/tiling/lifted_tetrahedron_set.py +54 -0
  444. snappy/tiling/real_hash_dict.py +164 -0
  445. snappy/tiling/test.py +23 -0
  446. snappy/tiling/tile.py +215 -0
  447. snappy/tiling/triangle.py +33 -0
  448. snappy/tkterminal.py +920 -0
  449. snappy/twister/__init__.py +20 -0
  450. snappy/twister/main.py +646 -0
  451. snappy/twister/surfaces/S_0_1 +3 -0
  452. snappy/twister/surfaces/S_0_2 +3 -0
  453. snappy/twister/surfaces/S_0_4 +7 -0
  454. snappy/twister/surfaces/S_0_4_Lantern +8 -0
  455. snappy/twister/surfaces/S_1 +3 -0
  456. snappy/twister/surfaces/S_1_1 +4 -0
  457. snappy/twister/surfaces/S_1_2 +5 -0
  458. snappy/twister/surfaces/S_1_2_5 +6 -0
  459. snappy/twister/surfaces/S_2 +6 -0
  460. snappy/twister/surfaces/S_2_1 +8 -0
  461. snappy/twister/surfaces/S_2_heeg +10 -0
  462. snappy/twister/surfaces/S_3 +8 -0
  463. snappy/twister/surfaces/S_3_1 +10 -0
  464. snappy/twister/surfaces/S_4_1 +12 -0
  465. snappy/twister/surfaces/S_5_1 +14 -0
  466. snappy/twister/surfaces/heeg_fig8 +9 -0
  467. snappy/twister/twister_core.cpython-313-darwin.so +0 -0
  468. snappy/upper_halfspace/__init__.py +146 -0
  469. snappy/upper_halfspace/ideal_point.py +26 -0
  470. snappy/verify/__init__.py +13 -0
  471. snappy/verify/canonical.py +542 -0
  472. snappy/verify/complex_volume/__init__.py +18 -0
  473. snappy/verify/complex_volume/adjust_torsion.py +86 -0
  474. snappy/verify/complex_volume/closed.py +168 -0
  475. snappy/verify/complex_volume/compute_ptolemys.py +90 -0
  476. snappy/verify/complex_volume/cusped.py +56 -0
  477. snappy/verify/complex_volume/extended_bloch.py +201 -0
  478. snappy/verify/cusp_translations.py +85 -0
  479. snappy/verify/edge_equations.py +80 -0
  480. snappy/verify/exceptions.py +254 -0
  481. snappy/verify/hyperbolicity.py +224 -0
  482. snappy/verify/interval_newton_shapes_engine.py +523 -0
  483. snappy/verify/interval_tree.py +400 -0
  484. snappy/verify/krawczyk_shapes_engine.py +518 -0
  485. snappy/verify/maximal_cusp_area_matrix/__init__.py +46 -0
  486. snappy/verify/maximal_cusp_area_matrix/cusp_tiling_engine.py +419 -0
  487. snappy/verify/maximal_cusp_area_matrix/cusp_translate_engine.py +153 -0
  488. snappy/verify/real_algebra.py +286 -0
  489. snappy/verify/shapes.py +25 -0
  490. snappy/verify/short_slopes.py +200 -0
  491. snappy/verify/square_extensions.py +1005 -0
  492. snappy/verify/test.py +78 -0
  493. snappy/verify/upper_halfspace/__init__.py +9 -0
  494. snappy/verify/upper_halfspace/extended_matrix.py +100 -0
  495. snappy/verify/upper_halfspace/finite_point.py +283 -0
  496. snappy/verify/upper_halfspace/ideal_point.py +426 -0
  497. snappy/verify/volume.py +128 -0
  498. snappy/version.py +2 -0
  499. snappy-3.2.dist-info/METADATA +58 -0
  500. snappy-3.2.dist-info/RECORD +503 -0
  501. snappy-3.2.dist-info/WHEEL +5 -0
  502. snappy-3.2.dist-info/entry_points.txt +2 -0
  503. snappy-3.2.dist-info/top_level.txt +28 -0
@@ -0,0 +1,1744 @@
1
+ #version 150
2
+
3
+ // GLSL version 1.50 corresponds to OpenGL 3.2 which is the version we target.
4
+
5
+ // History:
6
+ //
7
+ // This code was mostly written by Matthias Goerner during the
8
+ // "Illustrating Mathematics" workshop at ICERM in Fall 2019.
9
+ //
10
+ // Parts of it are taken from Cohomology fractals at
11
+ // https://github.com/henryseg/cohomology_fractals/tree/master/shaders
12
+ // The authors of Cohomology fractals and its history are listed at
13
+ // https://github.com/henryseg/cohomology_fractals/blob/master/README.md
14
+ //
15
+
16
+ #define COLOR_SCHEME 1
17
+
18
+ //--------------------------------------------
19
+ //Global Variables
20
+ //--------------------------------------------
21
+ out vec4 out_FragColor;
22
+
23
+ //-------------------------------------------
24
+ //Translation & Utility Variables
25
+ //--------------------------------------------
26
+
27
+ uniform vec2 screenResolution;
28
+ uniform float viewScale;
29
+ uniform bool crosshairs;
30
+
31
+ uniform int currentTetIndex;
32
+ uniform mat4 currentBoost;
33
+ uniform float currentWeight;
34
+
35
+ uniform int maxSteps;
36
+ uniform float maxDist;
37
+ uniform int subpixelCount;
38
+ uniform float edgeThicknessParam;
39
+ uniform float contrast;
40
+
41
+ const int perspectiveTypeMaterial = 0;
42
+ const int perspectiveTypeIdeal = 1;
43
+ const int perspectiveTypeHyperideal = 2;
44
+
45
+ uniform int perspectiveType;
46
+ uniform int viewMode;
47
+ uniform int multiScreenShot;
48
+ uniform vec2 tile;
49
+ uniform vec2 numTiles;
50
+ uniform bool noGradient;
51
+ uniform bool showElevation = false;
52
+
53
+ // Convention: ##NAME## names a compile time constant.
54
+ // The string ##NAME## is replaced by the code in __init__.py
55
+ // by looking up its value in the dictionary constants_dict.
56
+
57
+ layout (std140) uniform TetrahedraCombinatorics
58
+ {
59
+ int otherTetNums[4 * ##num_tets##];
60
+ int otherFaceNums[4 * ##num_tets##];
61
+ };
62
+
63
+ uniform float weights[4 * ##num_tets##];
64
+
65
+ layout (std140) uniform TetrahedraBasics
66
+ {
67
+ vec4 R13Vertices[4 * ##num_tets##];
68
+ vec4 planes[4 * ##num_tets##];
69
+ mat4 SO13tsfms[4 * ##num_tets##];
70
+ };
71
+
72
+ layout (std140) uniform Colors
73
+ {
74
+ int face_color_indices[4 * ##num_tets##];
75
+ int edge_color_indices[6 * ##num_tets##];
76
+ int vertex_color_indices[4 * ##num_tets##];
77
+ };
78
+
79
+ uniform bool desaturate_edges = false;
80
+
81
+ uniform float gradientThresholds[5];
82
+ uniform vec3 gradientColours[5];
83
+
84
+ uniform float edgeTubeRadiusParam;
85
+
86
+ uniform float lightBias;
87
+ uniform float lightFalloff;
88
+ uniform float brightness;
89
+ const vec4 lightSourcePosition = vec4(1.0, 0.0, 0.7, 0.0);
90
+
91
+ uniform bool isNonGeometric;
92
+ uniform sampler2D nonGeometricTexture;
93
+ uniform sampler2D eyeTexture;
94
+
95
+ const int num_tets = ##num_tets##;
96
+ const int num_edges = ##num_edges##;
97
+ const int num_cusps = ##num_cusps##;
98
+
99
+ #if ##finiteTrig##
100
+ layout (std140) uniform TetrahedraEdges
101
+ {
102
+ // Ends of edge 01 are 0 + 12 * tetNum and 1 + 12 * tetNum
103
+ // Ends of edge 02 are 2 + 12 * tetNum and 3 + 12 * tetNum
104
+ // Ends of edge 12 are 4 + 12 * tetNum and 5 + 12 * tetNum
105
+ // Ends of edge 03 ...
106
+ // Ends of edge 13 ...
107
+ // Ends of edge 23 are 10 + 12 * tetNum and 11 + 12 * tetNum
108
+ //
109
+ // Also see edgeToVertices
110
+ vec4 R13EdgeEnds[12 * ##num_tets##];
111
+ };
112
+
113
+ uniform float vertexSphereRadiusParam;
114
+
115
+ #else
116
+
117
+ // For an incomplete cusp, the Margulis tube is a cylinder about
118
+ // the geodesic the triangulation spins about. In other words,
119
+ // it is the cylinder fixed by the peripheral group of that cusp.
120
+ // We encode it by its two end points and cosh(radius)^2/2.
121
+ layout (std140) uniform MargulisTubes
122
+ {
123
+ vec4 margulisTubeTails[4 * ##num_tets##];
124
+ vec4 margulisTubeHeads[4 * ##num_tets##];
125
+ };
126
+ uniform float margulisTubeRadiusParams[4 * ##num_tets##];
127
+
128
+ #if defined(num_geodesic_segments) && num_geodesic_segments > 0
129
+ layout (std140) uniform geodesics
130
+ {
131
+ vec4 geodesicTails[num_geodesic_segments];
132
+ vec4 geodesicHeads[num_geodesic_segments];
133
+ int geodesicIndex[num_geodesic_segments];
134
+ float geodesicTubeRadiusParam[num_geodesic_segments];
135
+ int geodesicOffsets[##num_tets## + 1];
136
+ };
137
+ #endif
138
+
139
+ #if !defined(num_eyeballs)
140
+ #define num_eyeballs 0
141
+ #endif
142
+
143
+ #if num_eyeballs > 0
144
+ layout (std140) uniform eyeballs
145
+ {
146
+ vec4 eyeballPositions[num_eyeballs];
147
+ mat4 eyeballInvEmbeddings[num_eyeballs];
148
+ mat4 eyeballEmbeddings[num_eyeballs];
149
+ int eyeballOffsets[##num_tets## + 1];
150
+ };
151
+ uniform float eyeballRadius;
152
+
153
+ #if eyeball_type == 2
154
+ float eyeballRadiusParam = cosh(eyeballRadius) * cosh(eyeballRadius);
155
+ #else
156
+ float space_ship_width = 0.4;
157
+ float space_ship_fold_width = 0.13;
158
+ float space_ship_fold_height = 0.3;
159
+
160
+ vec4 space_ship_top_plane = vec4(0.0, 0.0, -1.0, 0.0);
161
+ vec4 space_ship_edges[2] = vec4[2](
162
+ vec4(0.0, 1.0 / space_ship_width, 0.0, 1.0),
163
+ vec4(0.0, -1.0 / space_ship_width, 0.0, 1.0));
164
+ vec4 space_ship_folds[2] = vec4[2](
165
+ vec4(0.0, 1.0 / space_ship_fold_width, 1.0 / space_ship_fold_height, 1.0),
166
+ vec4(0.0, -1.0 / space_ship_fold_width, 1.0 / space_ship_fold_height, 1.0));
167
+ float b = length(vec2(space_ship_fold_height, 1.0));
168
+ vec4 space_ship_back_plane = vec4(sinh(eyeballRadius), 0.0, 0.0, -b * cosh(eyeballRadius));
169
+ #endif
170
+
171
+ #endif
172
+
173
+ uniform float horosphereScales[4 * ##num_tets##];
174
+
175
+ #if defined(num_additional_horospheres) && num_additional_horospheres > 0
176
+ layout (std140) uniform additionalHorospheres
177
+ {
178
+ vec4 horosphereVec[num_additional_horospheres];
179
+ int horosphereCuspIndex[num_additional_horospheres];
180
+ int horosphereOffsets[##num_tets## + 1];
181
+ };
182
+
183
+ #endif
184
+
185
+ #if defined(has_edge_midpoints)
186
+ layout (std140) uniform edgeMidpoints
187
+ {
188
+ vec4 edgeMidpointVec[6 * ##num_tets##];
189
+ };
190
+
191
+ uniform float edgeMidpointRadiusParam;
192
+ #endif
193
+
194
+ // cosh(r)^2 where r is the radius of the sphere
195
+ // about the center of the tetrahedron.
196
+ uniform float insphereRadiusParams[##num_tets##];
197
+
198
+ // Matrix to convert between coordinates where the cusp is at
199
+ // infinity and the space of the tetrahedron
200
+ layout (std140) uniform TetCuspMatrices
201
+ {
202
+ mat4 tetToCuspMatrices[4 * ##num_tets##];
203
+ mat4 cuspToTetMatrices[4 * ##num_tets##];
204
+ };
205
+
206
+ uniform vec2 logAdjustments[4 * ##num_tets##];
207
+ uniform mat2 toStandardTorusMatrices[4 * ##num_tets##];
208
+
209
+ const float peripheralCurveThickness = 0.015;
210
+
211
+ #if COLOR_SCHEME == 1
212
+ const vec3 longitudeColor = vec3( 1.0 , 1.0 , 1.0 );
213
+ const vec3 meridianColor = vec3( 0.5 , 0.5 , 0.5 );
214
+ #else
215
+ const vec3 longitudeColor = vec3( 1.0 , 0.2 , 0.2 );
216
+ const vec3 meridianColor = vec3( 0.2 , 1.0 , 0.2 );
217
+ #endif
218
+
219
+ #endif
220
+
221
+ // Colouring function. All components are in the range [0...1], including hue.
222
+ // from http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
223
+ vec3 hsv2rgb(vec3 c)
224
+ {
225
+ vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
226
+ vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
227
+ return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
228
+ }
229
+
230
+ // Lorentz dot product with signature -+++
231
+ float
232
+ R13Dot(vec4 u, vec4 v)
233
+ {
234
+ return - u.x*v.x + u.y*v.y + u.z*v.z + u.w*v.w;
235
+ }
236
+
237
+ vec4
238
+ R13Normalise(vec4 v)
239
+ {
240
+ return v * inversesqrt(abs(R13Dot(v,v)));
241
+ }
242
+
243
+ // Given a direction vector and a point on the hyperbolic model, produces
244
+ // a unit tangent vector (in Minkowski space) at that point.
245
+ //
246
+ // It does by subtracting a suitable multiple of point from direction to
247
+ // make it orthogonal to point and then normalising.
248
+ vec4
249
+ makeUnitTangentVector(vec4 dir, vec4 point)
250
+ {
251
+ // Make dir orthogonal to point.
252
+ // Note that R13Dot(point, point) == -1, so we add instead of
253
+ // subtract.
254
+ vec4 t = dir + R13Dot(dir, point) * point;
255
+
256
+ return R13Normalise(t);
257
+ }
258
+
259
+ float
260
+ geodesicParameterPlanes(vec4 samplePoint, vec4 dualPoint1, vec4 dualPoint2){
261
+ // "distance" from a geodesic defined by two (assumed perpendicular) geodesic planes, this is not quite distance, need to asinh(sqrt( result ))
262
+
263
+ float dot1 = -R13Dot(samplePoint, dualPoint1);
264
+ vec4 dualPointPerp = R13Normalise(dualPoint2 - R13Dot(dualPoint1, dualPoint2) * dualPoint1); // should be precalculated if this is a main feature
265
+ float dot2 = -R13Dot(samplePoint, dualPointPerp);
266
+
267
+ return dot1*dot1 + dot2*dot2;
268
+ }
269
+
270
+ float
271
+ triangleBdryParam(vec4 samplePoint, int tetNum, int exit_face){
272
+ vec4 exit_dual_point = planes[4*tetNum + exit_face];
273
+ float smallest_p = 100000000.0;
274
+ for(int face=0; face<4; face++){
275
+ if(face != exit_face){ // find p when we hit that face
276
+ int index = 4*tetNum + face;
277
+ float new_p = geodesicParameterPlanes(samplePoint, exit_dual_point, planes[index]);
278
+ if(new_p < smallest_p){
279
+ smallest_p = new_p;
280
+ }
281
+ }
282
+ }
283
+ return smallest_p;
284
+ }
285
+
286
+ /// --- Ray-trace code --- ///
287
+
288
+ // Kind of object a ray hit.
289
+
290
+ const int object_type_nothing = 0;
291
+ const int object_type_face = 1;
292
+ const int object_type_edge_cylinder_enter = 2;
293
+ const int object_type_edge_cylinder_exit = 3;
294
+ const int object_type_horosphere_enter = 4;
295
+ const int object_type_horosphere_exit = 5;
296
+ const int object_type_edge_fan = 6;
297
+ const int object_type_insphere = 7;
298
+ const int object_type_vertex_sphere = 8;
299
+ const int object_type_margulis_tube_enter = 9;
300
+ const int object_type_margulis_tube_exit = 10;
301
+ const int object_type_elevation_enter = 11;
302
+ const int object_type_elevation_exit = 12;
303
+ const int object_type_geodesic_tube = 13;
304
+ const int object_type_additional_horosphere = 14;
305
+ const int object_type_eyeball = 15;
306
+ const int object_type_edge_midpoint = 16;
307
+
308
+ // A ray consists of a point in the hyperbolid model and a
309
+ // unit tangent vector dir orthogonal to the point with respect
310
+ // to the Lorentz product.
311
+ struct Ray
312
+ {
313
+ vec4 point;
314
+ vec4 dir;
315
+ };
316
+
317
+ // Ray with extra information what object was hit.
318
+ struct RayHit
319
+ {
320
+ Ray ray;
321
+ // What tetrahedron we are in.
322
+ int tet_num;
323
+ vec4 light_source;
324
+ // Distance the ray traveled from eye so far
325
+ float dist;
326
+ float weight;
327
+ float distWhenLeavingCusp;
328
+ // Type of object hit
329
+ int object_type;
330
+ // Index of object (within the tetrahedron), e.g.,
331
+ // 0-3 for horospheres, 0-5 for edges.
332
+ int object_index;
333
+
334
+ int object_subindex;
335
+ };
336
+
337
+ bool traceInsideVertexNeighborhood()
338
+ {
339
+ #if num_eyeballs > 0
340
+ return eyeballOffsets[##num_tets##] > 0;
341
+ #else
342
+ return false;
343
+ #endif
344
+ }
345
+
346
+ // We distinguish between:
347
+ // - colored ray hits: the geometry is lit, e.g., the cylinder
348
+ // about an edge reacts to light)
349
+ // - valued ray hits: we use a value such as the distance or cohomology
350
+ // fractal weight to compute a color using a color gradient
351
+ //
352
+ // Note that for subsampling, we need to average the value before
353
+ // applying the color gradient.
354
+ //
355
+ bool isColored(RayHit ray_hit)
356
+ {
357
+ return !(
358
+ ray_hit.object_type == object_type_nothing ||
359
+ ray_hit.object_type == object_type_face);
360
+ }
361
+
362
+ vec4
363
+ pointAdvancedByParam(Ray ray, float p)
364
+ {
365
+ return R13Normalise(ray.point + p * ray.dir );
366
+ }
367
+
368
+ // Advances ray by distance atanh(p).
369
+ //
370
+ // It is often more convenient to work with tanh(distance) rather than
371
+ // distance and we refer to tanh(distance) as "distParam".
372
+ void
373
+ advanceRayByDistParam(inout Ray ray, float p)
374
+ {
375
+ ray.point = pointAdvancedByParam(ray, p);
376
+ ray.dir = makeUnitTangentVector(ray.dir, ray.point);
377
+ }
378
+
379
+ // Returned as distParam by some methods to indicate that ray does not
380
+ // intersect object.
381
+ const float unreachableDistParam = 1000.0;
382
+
383
+ // Returns the real roots of the equation a * x^2 + b * x + c = 0, but
384
+ // each root is returned only if it is less than min_val.
385
+ // The existence of no such root is indicated by returning
386
+ // unreachableDistParam.
387
+ vec2
388
+ realRootsOfQuadratic(float a, float b, float c,
389
+ float min_val)
390
+ {
391
+ float d = b * b - 4 * a * c;
392
+ if (d < 0) {
393
+ return vec2(unreachableDistParam, unreachableDistParam);;
394
+ }
395
+ float offset = sign(a) * sqrt(d);
396
+ vec2 result = vec2(-b - offset, -b + offset) / (2 * a);
397
+ if (result.y < min_val) {
398
+ return vec2(unreachableDistParam, unreachableDistParam);;
399
+ }
400
+ if (result.x < min_val) {
401
+ return vec2(unreachableDistParam, result.y);
402
+ }
403
+ return result;
404
+ }
405
+
406
+ //--------------------------------------------
407
+ // Ray intersections
408
+ //
409
+ // Functions to compute the distParam (tanh(distance)) for the intersection
410
+ // of a ray with some object. Only the intersection of the ray entering an
411
+ // object is returned. No intersection is indicated by unreachableDistParam.
412
+
413
+ // Intersection with plane.
414
+ // The plane is given by all points such that the inner product
415
+ // of the point and the planeEqn is zero.
416
+ float
417
+ distParamForPlaneIntersection(Ray ray,
418
+ vec4 planeEqn)
419
+ {
420
+ // solve:
421
+ // R13Dot(planeEqn, ray.point + p * ray.dir) = 0
422
+ // R13Dot(planeEqn, ray.point) + p * R13Dot(planeEqn, ray.dir) = 0
423
+
424
+ float denom = R13Dot(planeEqn, ray.dir);
425
+ if(denom == 0.0) {
426
+ return unreachableDistParam;
427
+ }
428
+ return -R13Dot(planeEqn, ray.point) / denom;
429
+ }
430
+
431
+ // Intersection with sphere about given center (in hyperboloid model).
432
+ // The last parameter is the cosh(radius)^2.
433
+ vec2
434
+ distParamsForSphereIntersection(Ray ray,
435
+ vec4 center, float sphereRadiusParam)
436
+ {
437
+ float startDot = R13Dot(center, ray.point);
438
+ float dirDot = R13Dot(center, ray.dir);
439
+
440
+ return realRootsOfQuadratic(
441
+ dirDot * dirDot + sphereRadiusParam,
442
+ 2.0 * dirDot * startDot,
443
+ startDot * startDot - sphereRadiusParam,
444
+ 0.0);
445
+ }
446
+
447
+ // Intersection with horosphere defined by given light-like vector.
448
+ // The horosphere consists of all points such that the inner product
449
+ // with the light-like vector is -1.
450
+ vec2
451
+ distParamsForHorosphereIntersection(Ray ray,
452
+ vec4 horosphere)
453
+ {
454
+ return distParamsForSphereIntersection(ray, horosphere, 1);
455
+ }
456
+
457
+ // Intersection with cylinder about the geodesic with the two given
458
+ // (light-like) endpoints.
459
+ // tubeRadiusParam is cosh(radius)^2/2.
460
+ // This function can detect intersections of the ray that happen
461
+ // some distance before the start point of the ray. To use this feature,
462
+ // set minDistParam to a negative value, namely to tanh(-distance),
463
+ // where distance is how far back we want to track the ray.
464
+ vec2
465
+ distParamsForTubeIntersection(Ray ray,
466
+ vec4[2] endpoints,
467
+ float tubeRadiusParam,
468
+ float minDistParam)
469
+ {
470
+ // The points p (with R13Dot(p,p) = -1) on a tube about a
471
+ // geodesic are given by
472
+ //
473
+ // -tubeRadiusParam * R13Dot(endpoints[0], endpoints[1])
474
+ // = R13Dot(endpoints[0],p) * R13Dot(endpoints[1],p)
475
+ //
476
+ // To see this, note that the isometries of the tube about
477
+ // the geodesic act on the light-like endpoints by multiplying
478
+ // them by s and 1/s, respectively, where s > 0. It is easy
479
+ // to check that the equation is invariant under this action.
480
+ //
481
+ // To compute the tubeRadiusParam in terms of the tube radius,
482
+ // place the endpoints at (1,-1,0,0) and (1,1,0,0) and p at
483
+ // (cosh(radius),0,sinh(radius),0). We obtain
484
+ //
485
+ // tubeRadiusParam = cosh(radius)^2/2
486
+ //
487
+ // The ray is parameterized by
488
+ //
489
+ // p = p0 / sqrt(-R13Dot(p0, p0))
490
+ //
491
+ // where
492
+ // p0 = ray.point + t * ray.dir.
493
+ //
494
+ // Putting p into the above equation and multiplying by
495
+ // -R13Dot(p0, p0), we obtain a quadratic equation we can solve for.
496
+
497
+ float start0Dot = R13Dot(endpoints[0], ray.point);
498
+ float dir0Dot = R13Dot(endpoints[0], ray.dir);
499
+ float start1Dot = R13Dot(endpoints[1], ray.point);
500
+ float dir1Dot = R13Dot(endpoints[1], ray.dir);
501
+ float endDot = R13Dot(endpoints[0], endpoints[1]);
502
+
503
+ return realRootsOfQuadratic(
504
+ dir0Dot * dir1Dot - endDot * tubeRadiusParam,
505
+ start0Dot * dir1Dot + start1Dot * dir0Dot,
506
+ start0Dot * start1Dot + endDot * tubeRadiusParam,
507
+ minDistParam);
508
+ }
509
+
510
+ //--------------------------------------------
511
+ // Object normals
512
+ //
513
+ // Function to compute the normal of an object at the given point
514
+
515
+
516
+ // Normal for a sphere about the center.
517
+ vec4
518
+ normalForSphere(vec4 point, vec4 center)
519
+ {
520
+ vec4 t = center - point;
521
+
522
+ return makeUnitTangentVector(t, point);
523
+ }
524
+
525
+ // Normal for a cylinder between the two given (light-like) endpoints.
526
+ vec4
527
+ normalForTube(vec4 point, vec4[2] endpoints)
528
+ {
529
+ vec4 t = endpoints[0] * R13Dot(point, endpoints[1])
530
+ + endpoints[1] * R13Dot(point, endpoints[0]);
531
+
532
+ return - makeUnitTangentVector(t, point);
533
+ }
534
+
535
+ //--------------------------------------------
536
+ // Object helpers
537
+ //
538
+ // Various helpers to obtain object representations from
539
+ // the uniforms.
540
+
541
+ // Indices of vertices that are the end points of an edge.
542
+ //
543
+ // Needs to be consistent with SnapPy/t3m conventions
544
+ // (i.e., t3m's OneSubsimplices).
545
+ const ivec2[6] edgeToVertices = ivec2[](ivec2(0, 1),
546
+ ivec2(0, 2),
547
+ ivec2(1, 2),
548
+ ivec2(0, 3),
549
+ ivec2(1, 3),
550
+ ivec2(2, 3));
551
+
552
+ // The two endpoints of an edge of a tetrahedron
553
+ vec4[2]
554
+ endpointsForEdge(int tet, int edge)
555
+ {
556
+ #if ##finiteTrig##
557
+ return vec4[](R13EdgeEnds[12 * tet + 2 * edge ],
558
+ R13EdgeEnds[12 * tet + 2 * edge + 1]);
559
+ #else
560
+ return vec4[](R13Vertices[4 * tet + edgeToVertices[edge].x],
561
+ R13Vertices[4 * tet + edgeToVertices[edge].y]);
562
+ #endif
563
+ }
564
+
565
+ #if !##finiteTrig##
566
+ // The two endpoints of a Margulis tube.
567
+ vec4[2]
568
+ endpointsForMargulisTube(int index)
569
+ {
570
+ return vec4[](margulisTubeTails[index],
571
+ margulisTubeHeads[index]);
572
+ }
573
+
574
+ // The equation for the horosphere about a vertex in a tetrahedron.
575
+ // index is 4 * tetIndex + vertex.
576
+ vec4
577
+ horosphereEqn(int index)
578
+ {
579
+ return horosphereScales[index] * R13Vertices[index];
580
+ }
581
+
582
+ #if defined(num_geodesic_segments) && num_geodesic_segments > 0
583
+ // The two endpoints of a geodesic
584
+ vec4[2]
585
+ endpointsForGeodesic(int index)
586
+ {
587
+ return vec4[](geodesicTails[index],
588
+ geodesicHeads[index]);
589
+ }
590
+ #endif
591
+
592
+ #endif
593
+
594
+ vec4
595
+ normalForRayHit(RayHit ray_hit)
596
+ {
597
+ #if ##finiteTrig##
598
+ if(ray_hit.object_type == object_type_vertex_sphere) {
599
+ int index = 4 * ray_hit.tet_num + ray_hit.object_index;
600
+ return normalForSphere(ray_hit.ray.point, R13Vertices[index]);
601
+ }
602
+ #else
603
+ if(ray_hit.object_type == object_type_insphere) {
604
+ return normalForSphere(ray_hit.ray.point, vec4(1,0,0,0));
605
+ }
606
+
607
+ if(ray_hit.object_type == object_type_horosphere_enter) {
608
+ int index = 4 * ray_hit.tet_num + ray_hit.object_index;
609
+ return horosphereEqn(index) - ray_hit.ray.point;
610
+ }
611
+
612
+ if(ray_hit.object_type == object_type_horosphere_exit) {
613
+ int index = 4 * ray_hit.tet_num + ray_hit.object_index;
614
+ return ray_hit.ray.point - horosphereEqn(index);
615
+ }
616
+
617
+ if(ray_hit.object_type == object_type_margulis_tube_enter) {
618
+ int index = 4 * ray_hit.tet_num + ray_hit.object_index;
619
+ return normalForTube(
620
+ ray_hit.ray.point,
621
+ endpointsForMargulisTube(index));
622
+ }
623
+
624
+ if(ray_hit.object_type == object_type_margulis_tube_exit) {
625
+ int index = 4 * ray_hit.tet_num + ray_hit.object_index;
626
+ return - normalForTube(
627
+ ray_hit.ray.point,
628
+ endpointsForMargulisTube(index));
629
+ }
630
+
631
+ #if defined(num_geodesic_segments) && num_geodesic_segments > 0
632
+ if (ray_hit.object_type == object_type_geodesic_tube) {
633
+ return normalForTube(
634
+ ray_hit.ray.point,
635
+ endpointsForGeodesic(ray_hit.object_index));
636
+ }
637
+ #endif
638
+
639
+ #if defined(num_additional_horospheres) && num_additional_horospheres > 0
640
+ if (ray_hit.object_type == object_type_additional_horosphere) {
641
+ return horosphereVec[ray_hit.object_index] - ray_hit.ray.point;
642
+ }
643
+ #endif
644
+
645
+ #if num_eyeballs > 0
646
+ if (ray_hit.object_type == object_type_eyeball) {
647
+ #if eyeball_type == 2
648
+ return normalForSphere(
649
+ ray_hit.ray.point, eyeballPositions[ray_hit.object_index]);
650
+ #else
651
+ vec4 local_normal;
652
+ if (ray_hit.object_subindex == 0) {
653
+ local_normal = space_ship_top_plane;
654
+ } else {
655
+ local_normal = R13Normalise(space_ship_folds[ray_hit.object_subindex - 1]);
656
+ }
657
+ vec4 normal = local_normal * eyeballEmbeddings[ray_hit.object_index];
658
+
659
+ if (R13Dot(ray_hit.ray.dir, normal) > 0) {
660
+ return normal;
661
+ } else {
662
+ return -normal;
663
+ }
664
+ #endif
665
+ }
666
+ #endif
667
+
668
+ #if defined(has_edge_midpoints)
669
+ if (ray_hit.object_type == object_type_edge_midpoint) {
670
+ int index = 6 * ray_hit.tet_num + ray_hit.object_index;
671
+ return normalForSphere(ray_hit.ray.point, edgeMidpointVec[index]);
672
+ }
673
+ #endif
674
+
675
+ #endif
676
+
677
+ if(ray_hit.object_type == object_type_edge_fan ||
678
+ ray_hit.object_type == object_type_elevation_enter ||
679
+ ray_hit.object_type == object_type_elevation_exit) {
680
+ int index = 4 * ray_hit.tet_num + ray_hit.object_index;
681
+ return planes[index];
682
+ }
683
+
684
+ if(ray_hit.object_type == object_type_edge_cylinder_enter) {
685
+ return normalForTube(
686
+ ray_hit.ray.point,
687
+ endpointsForEdge(ray_hit.tet_num, ray_hit.object_index));
688
+ }
689
+
690
+ if(ray_hit.object_type == object_type_edge_cylinder_exit) {
691
+ return - normalForTube(
692
+ ray_hit.ray.point,
693
+ endpointsForEdge(ray_hit.tet_num, ray_hit.object_index));
694
+ }
695
+
696
+ return vec4(0,1,0,0);
697
+ }
698
+
699
+ // Convert point in hyperboloid model to upper halfspace
700
+ // model.
701
+ // The vec3 result corresponds to result.x + result.y * i + result.z * j,
702
+ // i.e., the last component of the vec3 is the height.
703
+ vec3
704
+ hyperboloidToUpperHalfspace(vec4 h)
705
+ {
706
+ vec3 klein = h.yzw / h.x;
707
+ vec3 poincare = klein / (1.0 + sqrt(1.0 - dot(klein, klein)));
708
+ vec3 denom_helper = vec3(poincare.x - 1.0, poincare.yz);
709
+ float denom = dot(denom_helper, denom_helper);
710
+
711
+ return vec3(2.0 * poincare.yz, 1.0 - dot(poincare, poincare)) / denom;
712
+ }
713
+
714
+ #if !##finiteTrig##
715
+ // Compute the coordinates of a ray hit on a horosphere in the upper
716
+ // half space model such that the cusp is at infinity.
717
+ vec3
718
+ preferredUpperHalfspaceCoordinates(RayHit ray_hit)
719
+ {
720
+ int index = 4 * ray_hit.tet_num + ray_hit.object_index;
721
+
722
+ return hyperboloidToUpperHalfspace(
723
+ ray_hit.ray.point * tetToCuspMatrices[index]);
724
+ }
725
+
726
+ vec2
727
+ complexLog(vec2 z)
728
+ {
729
+ return vec2(log(length(z)), atan(z.y, z.x));
730
+ }
731
+
732
+ vec2
733
+ MLCoordinatesForRayHit(RayHit rayHit)
734
+ {
735
+ int index = 4 * rayHit.tet_num + rayHit.object_index;
736
+
737
+ vec3 pointUpperHalfspace = preferredUpperHalfspaceCoordinates(rayHit);
738
+ vec2 z = pointUpperHalfspace.xy;
739
+
740
+ if (rayHit.object_type == object_type_margulis_tube_enter ||
741
+ rayHit.object_type == object_type_margulis_tube_exit) {
742
+ z = complexLog(z) + logAdjustments[index];
743
+ }
744
+
745
+ return z * toStandardTorusMatrices[index];
746
+ }
747
+
748
+ int
749
+ peripheralCurveForMLCoordinates(vec2 ml_coordinates)
750
+ {
751
+ // Map R^2->torus
752
+ vec2 f = fract(ml_coordinates);
753
+
754
+ if ( f.y < peripheralCurveThickness ||
755
+ f.y > 1.0 - peripheralCurveThickness) {
756
+ return 2;
757
+ }
758
+
759
+ if ( f.x < peripheralCurveThickness ||
760
+ f.x > 1.0 - peripheralCurveThickness) {
761
+ return 1;
762
+ }
763
+
764
+ return 0;
765
+ }
766
+ #endif
767
+
768
+ // Compute the SO13 transform corresponding to the PSL(2,C)-matrix
769
+ // [[1, z], [0, 1]].
770
+ // Special case of the kernel's Moebius_to_O31 for upper unit triangular
771
+ // matrices.
772
+ mat4
773
+ parabolicSO13(vec2 z)
774
+ {
775
+ float t = dot(z, z) / 2.0;
776
+
777
+ return mat4( 1.0 + t, - t, z.x, z.y,
778
+ t, 1.0 - t, z.x, z.y,
779
+ z.x, -z.x, 1.0, 0.0,
780
+ z.y, -z.y, 0.0, 1.0 );
781
+ }
782
+
783
+ // Compute the SO13 transform corresponding to the PGL(2,C)-matrix
784
+ // [[ exp(z), 0], [0, 1]].
785
+ // Special case of the kernel's Moebius_to_O31 for diagonal matrices.
786
+ mat4
787
+ loxodromicSO13(vec2 z)
788
+ {
789
+ return mat4( cosh(z.x), sinh(z.x), 0.0, 0.0,
790
+ sinh(z.x), cosh(z.x), 0.0, 0.0,
791
+ 0.0, 0.0, cos(z.y), -sin(z.y),
792
+ 0.0, 0.0, sin(z.y), cos(z.y) );
793
+ }
794
+
795
+ void
796
+ ray_trace_through_hyperboloid_tet(inout RayHit ray_hit)
797
+ {
798
+ int entry_object_type = ray_hit.object_type;
799
+ int entry_object_index = ray_hit.object_index;
800
+
801
+ ///Given shape of a tet and a ray, find where the ray exits and through which face
802
+ float smallest_p = 100000000.0;
803
+
804
+ float horosphere_exit_param = -unreachableDistParam;
805
+
806
+ #if !##finiteTrig##
807
+ for (int vertex = 0; vertex < 4; vertex++) {
808
+ int index = 4 * ray_hit.tet_num + vertex;
809
+ if ( horosphereScales[index] != 0.0 ||
810
+ margulisTubeRadiusParams[index] > 0.50001) {
811
+
812
+ vec2 params;
813
+ if (horosphereScales[index] != 0.0) {
814
+ params = distParamsForHorosphereIntersection(
815
+ ray_hit.ray,
816
+ horosphereEqn(index));
817
+ } else {
818
+ params = distParamsForTubeIntersection(
819
+ ray_hit.ray,
820
+ endpointsForMargulisTube(index),
821
+ margulisTubeRadiusParams[index],
822
+ 0.0);
823
+ }
824
+
825
+ if (params.x < smallest_p) {
826
+ smallest_p = params.x;
827
+ if (horosphereScales[index] != 0.0) {
828
+ ray_hit.object_type = object_type_horosphere_enter;
829
+ } else {
830
+ ray_hit.object_type = object_type_margulis_tube_enter;
831
+ }
832
+ ray_hit.object_index = vertex;
833
+ }
834
+
835
+ if (traceInsideVertexNeighborhood()) {
836
+ if (params.y < smallest_p) {
837
+ horosphere_exit_param = params.y;
838
+ ray_hit.distWhenLeavingCusp = ray_hit.dist + atanh(params.y);
839
+
840
+ RayHit new_hit = ray_hit;
841
+ new_hit.object_index = vertex;
842
+ advanceRayByDistParam(new_hit.ray, params.y);
843
+
844
+ if (peripheralCurveForMLCoordinates(
845
+ MLCoordinatesForRayHit(new_hit)) > 0) {
846
+ smallest_p = params.y;
847
+
848
+ if (horosphereScales[index] != 0.0) {
849
+ ray_hit.object_type = object_type_horosphere_exit;
850
+ } else {
851
+ ray_hit.object_type = object_type_margulis_tube_exit;
852
+ }
853
+ ray_hit.object_index = vertex;
854
+ }
855
+ }
856
+ }
857
+ }
858
+ }
859
+ #endif
860
+
861
+ for(int face = 0; face < 4; face++) {
862
+ if (entry_object_type != object_type_face || entry_object_index != face) {
863
+ // find p when we hit that face
864
+ int index = 4 * ray_hit.tet_num + face;
865
+ if(R13Dot(ray_hit.ray.dir, planes[index]) > 0.0){
866
+ float p = distParamForPlaneIntersection(ray_hit.ray, planes[index]);
867
+ // if ((-10000.0 <= p) && (p < smallest_p)) {
868
+ if (p < smallest_p) {
869
+ /// negative values are ok if we have to go backwards a little to get through the face we are a little the wrong side of
870
+ /// Although this can apparently get caught in infinite loops in an edge
871
+
872
+ /// if we are on an edge then we don't in fact move as we go through this tet: t = 0.0
873
+ /// also allow tiny negative values, which will come up from floating point errors.
874
+ /// surface normals check should ensure that even in this case we make progress through
875
+ /// the triangles around an edge
876
+ smallest_p = p;
877
+ ray_hit.object_type = object_type_face;
878
+ ray_hit.object_index = face;
879
+ }
880
+ }
881
+ }
882
+ }
883
+
884
+ #if ##finiteTrig##
885
+ if (vertexSphereRadiusParam > 1.0001) {
886
+ for (int vertex = 0; vertex < 4; vertex++) {
887
+ int index = 4 * ray_hit.tet_num + vertex;
888
+ float p = distParamsForSphereIntersection(
889
+ ray_hit.ray,
890
+ R13Vertices[index],
891
+ vertexSphereRadiusParam).x;
892
+ if (p < smallest_p) {
893
+ smallest_p = p;
894
+ ray_hit.object_type = object_type_vertex_sphere;
895
+ ray_hit.object_index = vertex;
896
+ }
897
+ }
898
+ }
899
+ #else
900
+ {
901
+ float r = insphereRadiusParams[ray_hit.tet_num];
902
+
903
+ if (r > 1.0001) {
904
+ float p = distParamsForSphereIntersection(
905
+ ray_hit.ray,
906
+ vec4(1,0,0,0),
907
+ r).x;
908
+ if (p < smallest_p && (!traceInsideVertexNeighborhood() ||
909
+ p > horosphere_exit_param)) {
910
+ smallest_p = p;
911
+ ray_hit.object_type = object_type_insphere;
912
+ ray_hit.object_index = 0;
913
+ }
914
+ }
915
+ }
916
+
917
+ #if defined(has_edge_midpoints)
918
+ {
919
+ for (int edge = 0; edge < 6; edge++) {
920
+ int index = 6 * ray_hit.tet_num + edge;
921
+ float p = distParamsForSphereIntersection(
922
+ ray_hit.ray,
923
+ edgeMidpointVec[index],
924
+ edgeMidpointRadiusParam).x;
925
+ if (p < smallest_p) {
926
+ smallest_p = p;
927
+ ray_hit.object_type = object_type_edge_midpoint;
928
+ ray_hit.object_index = edge;
929
+ }
930
+ }
931
+ }
932
+ #endif
933
+
934
+ #if defined(num_geodesic_segments) && num_geodesic_segments > 0
935
+ for (int index = geodesicOffsets[ray_hit.tet_num];
936
+ index < geodesicOffsets[ray_hit.tet_num + 1];
937
+ index++) {
938
+
939
+ vec2 params = distParamsForTubeIntersection(
940
+ ray_hit.ray,
941
+ endpointsForGeodesic(index),
942
+ geodesicTubeRadiusParam[index],
943
+ 0.0);
944
+
945
+ if (params.x < smallest_p && (!traceInsideVertexNeighborhood() ||
946
+ params.x > horosphere_exit_param)) {
947
+ smallest_p = params.x;
948
+ ray_hit.object_type = object_type_geodesic_tube;
949
+ ray_hit.object_index = index;
950
+ }
951
+ }
952
+ #endif
953
+
954
+ #if defined(num_additional_horospheres) && num_additional_horospheres > 0
955
+ for (int index = horosphereOffsets[ray_hit.tet_num];
956
+ index < horosphereOffsets[ray_hit.tet_num + 1];
957
+ index++) {
958
+
959
+ vec2 params = distParamsForHorosphereIntersection(
960
+ ray_hit.ray,
961
+ horosphereVec[index]);
962
+
963
+ if (params.x < smallest_p) {
964
+ smallest_p = params.x;
965
+ ray_hit.object_type = object_type_additional_horosphere;
966
+ ray_hit.object_index = index;
967
+ }
968
+ }
969
+ #endif
970
+
971
+ #if num_eyeballs > 0
972
+ for (int index = eyeballOffsets[ray_hit.tet_num];
973
+ index < eyeballOffsets[ray_hit.tet_num + 1];
974
+ index++) {
975
+
976
+ #if eyeball_type == 2
977
+ vec2 params = distParamsForSphereIntersection(
978
+ ray_hit.ray,
979
+ eyeballPositions[index],
980
+ eyeballRadiusParam);
981
+
982
+ if (params.x < smallest_p) {
983
+ smallest_p = params.x;
984
+ ray_hit.object_type = object_type_eyeball;
985
+ ray_hit.object_index = index;
986
+ }
987
+ #else
988
+ Ray local_ray;
989
+ local_ray.point = ray_hit.ray.point * eyeballInvEmbeddings[index];
990
+ local_ray.dir = ray_hit.ray.dir * eyeballInvEmbeddings[index];
991
+
992
+ {
993
+ float param = distParamForPlaneIntersection(local_ray, vec4(0.0, 0.0, 1.0, 0.0));
994
+
995
+ if (param > 0 && param < smallest_p) {
996
+ if (ray_hit.dist + atanh(param) > 0.001) {
997
+ vec4 hit_point = pointAdvancedByParam(local_ray, param);
998
+ if ((dot(hit_point, space_ship_folds[0]) < 0.0 ||
999
+ dot(hit_point, space_ship_folds[1]) < 0.0) &&
1000
+ dot(hit_point, space_ship_back_plane) > 0.0 &&
1001
+ dot(hit_point, space_ship_edges[0]) > 0.0 &&
1002
+ dot(hit_point, space_ship_edges[1]) > 0.0) {
1003
+ smallest_p = param;
1004
+ ray_hit.object_type = object_type_eyeball;
1005
+ ray_hit.object_index = index;
1006
+ ray_hit.object_subindex = 0;
1007
+ }
1008
+ }
1009
+ }
1010
+ }
1011
+
1012
+ for (int s = 0; s < 2; s++) {
1013
+ float param = distParamForPlaneIntersection(local_ray, space_ship_folds[s]);
1014
+
1015
+ if (param > 0 && param < smallest_p) {
1016
+ if (ray_hit.dist + atanh(param) > 0.001) {
1017
+ vec4 hit_point = pointAdvancedByParam(local_ray, param);
1018
+
1019
+ if (dot(hit_point, space_ship_back_plane) > 0.0 &&
1020
+ dot(hit_point, space_ship_top_plane) > 0.0 &&
1021
+ dot(hit_point, space_ship_folds[1-s]) > 0.0) {
1022
+
1023
+ smallest_p = param;
1024
+ ray_hit.object_type = object_type_eyeball;
1025
+ ray_hit.object_index = index;
1026
+ ray_hit.object_subindex = 1 + s;
1027
+ }
1028
+ }
1029
+ }
1030
+ }
1031
+ #endif
1032
+ }
1033
+ #endif
1034
+
1035
+ #endif
1036
+
1037
+ if (edgeTubeRadiusParam > 0.500001) {
1038
+
1039
+ #if ##finiteTrig##
1040
+ float backDistParam = 0.0;
1041
+ #else
1042
+ float backDistParam = tanh(ray_hit.distWhenLeavingCusp-ray_hit.dist);
1043
+ #endif
1044
+
1045
+ for (int edge = 0; edge < 6; edge++) {
1046
+
1047
+ vec2 params = distParamsForTubeIntersection(
1048
+ ray_hit.ray,
1049
+ endpointsForEdge(ray_hit.tet_num, edge),
1050
+ edgeTubeRadiusParam,
1051
+ backDistParam);
1052
+
1053
+ if (params.x < smallest_p && (!traceInsideVertexNeighborhood() ||
1054
+ params.x > horosphere_exit_param)) {
1055
+ smallest_p = params.x;
1056
+ ray_hit.object_type = object_type_edge_cylinder_enter;
1057
+ ray_hit.object_index = edge;
1058
+ }
1059
+ if (params.y < smallest_p && (!traceInsideVertexNeighborhood() ||
1060
+ params.y > horosphere_exit_param)) {
1061
+ smallest_p = params.y;
1062
+ ray_hit.object_type = object_type_edge_cylinder_exit;
1063
+ ray_hit.object_index = edge;
1064
+ }
1065
+ }
1066
+ }
1067
+
1068
+ ray_hit.dist += atanh(smallest_p);
1069
+ advanceRayByDistParam(ray_hit.ray, smallest_p);
1070
+
1071
+ if(edgeThicknessParam > 0.00001) {
1072
+ if (ray_hit.object_type == object_type_face) {
1073
+ if (!traceInsideVertexNeighborhood() ||
1074
+ smallest_p > horosphere_exit_param) {
1075
+ if(triangleBdryParam(ray_hit.ray.point, ray_hit.tet_num, ray_hit.object_index) < edgeThicknessParam) {
1076
+ ray_hit.object_type = object_type_edge_fan;
1077
+ }
1078
+ }
1079
+ }
1080
+ }
1081
+ }
1082
+
1083
+ int
1084
+ is_elevation_hit(float old_weight, float new_weight)
1085
+ {
1086
+ const float eps = 1e-4;
1087
+ float o = old_weight - eps;
1088
+ float n = new_weight - eps;
1089
+
1090
+ if (o * n < 0.0) {
1091
+ if (n < 0.0) {
1092
+ return object_type_elevation_enter;
1093
+ } else {
1094
+ return object_type_elevation_exit;
1095
+ }
1096
+ }
1097
+
1098
+ return object_type_nothing;
1099
+ }
1100
+
1101
+ void
1102
+ ray_trace(inout RayHit ray_hit) {
1103
+
1104
+ for(int i = 0; i < maxSteps; i++){
1105
+ ray_trace_through_hyperboloid_tet(ray_hit);
1106
+
1107
+ if (ray_hit.object_type != object_type_face) {
1108
+ break;
1109
+ }
1110
+
1111
+ if (ray_hit.dist > maxDist) {
1112
+ break;
1113
+ }
1114
+
1115
+ // in fact pow(sinh(radius in hyperbolic units),2.0). However, sinh^2 is monotonic for
1116
+ // positive values so we get correct behaviour by comparing without the sinh^2.
1117
+ int index = 4 * ray_hit.tet_num + ray_hit.object_index;
1118
+
1119
+ float new_weight = ray_hit.weight + weights[ index ];
1120
+
1121
+ if (showElevation) {
1122
+ int elevation_object_type =
1123
+ is_elevation_hit(ray_hit.weight, new_weight);
1124
+
1125
+ if (elevation_object_type != object_type_nothing) {
1126
+ ray_hit.object_type = elevation_object_type;
1127
+ break;
1128
+ }
1129
+ }
1130
+
1131
+ ray_hit.weight = new_weight;
1132
+
1133
+ ray_hit.object_index = otherFaceNums[ index ];
1134
+ mat4 tsfm = SO13tsfms[ index ];
1135
+
1136
+ ray_hit.light_source = ray_hit.light_source * tsfm;
1137
+ ray_hit.ray.point = ray_hit.ray.point * tsfm;
1138
+ ray_hit.ray.dir = R13Normalise( ray_hit.ray.dir * tsfm );
1139
+ ray_hit.tet_num = otherTetNums[ index ];
1140
+ }
1141
+ }
1142
+
1143
+
1144
+
1145
+ /// --- Colour gradient code --- ///
1146
+
1147
+ int find_band(float t, float thresholds[5]){
1148
+ for(int j = 1; j < 4; j++) {
1149
+ if(t < thresholds[j]) {
1150
+ return j;
1151
+ }
1152
+ }
1153
+ return 4;
1154
+ }
1155
+
1156
+ vec3 general_gradient(float t, float thresholds[5], vec3 colours[5]){
1157
+ int i = find_band(t, thresholds);
1158
+ return mix(colours[i-1],
1159
+ colours[i],
1160
+ (t - thresholds[i-1])/(thresholds[i] - thresholds[i-1]));
1161
+ }
1162
+
1163
+ // Given the (average) value for a ray hit, apply gradient to get
1164
+ // color.
1165
+ vec3 colorForValue(float value)
1166
+ {
1167
+ if (noGradient) {
1168
+ return vec3(value);
1169
+ }
1170
+
1171
+ value = contrast * value;
1172
+ value = 0.5 + 0.5 * value/ (abs(value) + 1.0); //faster than atan, similar
1173
+
1174
+ return general_gradient(value, gradientThresholds, gradientColours);
1175
+ }
1176
+
1177
+ struct MaterialParams
1178
+ {
1179
+ vec3 ambient;
1180
+ vec3 diffuse;
1181
+ vec3 specular;
1182
+
1183
+ float shininess;
1184
+ };
1185
+
1186
+ MaterialParams
1187
+ material_params(RayHit ray_hit)
1188
+ {
1189
+ MaterialParams result;
1190
+
1191
+ result.diffuse = vec3(0.2, 0.6, 0.3);
1192
+ result.ambient = 0.5 * result.diffuse;
1193
+ result.specular = vec3(0.5, 0.5, 0.5);
1194
+ result.shininess = 20;
1195
+
1196
+ #if ##finiteTrig##
1197
+ if (ray_hit.object_type == object_type_vertex_sphere) {
1198
+ int index = 4 * ray_hit.tet_num + ray_hit.object_index;
1199
+ int color_index = vertex_color_indices[index];
1200
+
1201
+ result.diffuse = hsv2rgb(vec3(float(color_index)/float(num_cusps), 0.25, 1.0));
1202
+ result.ambient = 0.5 * result.diffuse;
1203
+ }
1204
+ #else
1205
+ if (ray_hit.object_type == object_type_horosphere_enter ||
1206
+ ray_hit.object_type == object_type_horosphere_exit ||
1207
+ ray_hit.object_type == object_type_margulis_tube_enter ||
1208
+ ray_hit.object_type == object_type_margulis_tube_exit) {
1209
+
1210
+ int index = 4 * ray_hit.tet_num + ray_hit.object_index;
1211
+ int color_index = vertex_color_indices[index];
1212
+
1213
+ #if COLOR_SCHEME == 1
1214
+ result.diffuse = hsv2rgb(vec3(float(color_index)/float(num_cusps), 0.25, 1.0));
1215
+ #else
1216
+ result.diffuse =
1217
+ vec3(0.5, 0.5, 0.5)
1218
+ + sin(color_index) * vec3( 0.3, -0.3, 0.0)
1219
+ + cos(color_index) * vec3(0.15, 0.15, -0.3);
1220
+ #endif
1221
+ result.ambient = 0.5 * result.diffuse;
1222
+
1223
+ int peripheralCurve =
1224
+ peripheralCurveForMLCoordinates(
1225
+ MLCoordinatesForRayHit(ray_hit));
1226
+
1227
+ if (peripheralCurve == 1) {
1228
+ result.diffuse = longitudeColor;
1229
+ result.ambient = result.diffuse;
1230
+ }
1231
+ if (peripheralCurve == 2) {
1232
+ result.diffuse = meridianColor;
1233
+ result.ambient = result.diffuse;
1234
+ }
1235
+ }
1236
+
1237
+ if (ray_hit.object_type == object_type_insphere) {
1238
+ result.diffuse = hsv2rgb(vec3(float(ray_hit.tet_num)/float(num_tets), 0.5, 1.0));
1239
+
1240
+ result.diffuse *= 0.5;
1241
+
1242
+ result.ambient = 0.5 * result.diffuse;
1243
+ }
1244
+
1245
+ #endif
1246
+
1247
+ if (ray_hit.object_type == object_type_edge_fan) {
1248
+ int index = 4 * ray_hit.tet_num + ray_hit.object_index;
1249
+ int color_index = face_color_indices[index];
1250
+ result.diffuse = hsv2rgb(vec3(float(color_index)/float(2*num_tets), 0.75, 0.5));
1251
+ result.ambient = 0.5 * result.diffuse;
1252
+ }
1253
+
1254
+ if (ray_hit.object_type == object_type_edge_cylinder_enter) {
1255
+ int index = 6 * ray_hit.tet_num + ray_hit.object_index;
1256
+ int color_index = edge_color_indices[index];
1257
+
1258
+ //using num_tets = num_edges
1259
+
1260
+ #if COLOR_SCHEME == 1
1261
+ result.diffuse = hsv2rgb(
1262
+ vec3(float(color_index)/float(num_edges),
1263
+ desaturate_edges ? 0.24 : 1.0,
1264
+ 1.0));
1265
+ #else
1266
+ result.diffuse =
1267
+ vec3(0.5, 0.5, 0.5)
1268
+ + sin(color_index) * vec3( 0.3, -0.3, 0.0)
1269
+ + cos(color_index) * vec3(0.15, 0.15, -0.3);
1270
+ #endif
1271
+
1272
+ result.ambient = 0.5 * result.diffuse;
1273
+ }
1274
+
1275
+ if (ray_hit.object_type == object_type_edge_cylinder_exit) {
1276
+ int index = 6 * ray_hit.tet_num + ray_hit.object_index;
1277
+ int color_index = edge_color_indices[index];
1278
+
1279
+ //using num_tets = num_edges
1280
+ result.diffuse = 0.3 * hsv2rgb(vec3(float(color_index)/float(num_tets), 1.0, 1.0));
1281
+ result.ambient = 0.5 * result.diffuse;
1282
+ }
1283
+
1284
+ if (ray_hit.object_type == object_type_elevation_enter) {
1285
+ result.diffuse = vec3(0.3,0.7,0.3);
1286
+ result.ambient = 0.5 * result.diffuse;
1287
+ }
1288
+
1289
+ if (ray_hit.object_type == object_type_elevation_exit) {
1290
+ result.diffuse = vec3(0.7,0.3,0.3);
1291
+ result.ambient = 0.5 * result.diffuse;
1292
+ }
1293
+
1294
+ #if defined(num_geodesic_segments) && num_geodesic_segments > 0
1295
+ if (ray_hit.object_type == object_type_geodesic_tube) {
1296
+ int index = geodesicIndex[ray_hit.object_index];
1297
+
1298
+ // The user wants to switch geodesics off and on while
1299
+ // their colors stay stable.
1300
+ //
1301
+ // Thus, we cannot divide the color circle equally.
1302
+ //
1303
+ // Instead, we multiply the index by the golden angle
1304
+ // pi * (3 - sqrt(5)) radians
1305
+ // so that no geodesics hit the same color.
1306
+ //
1307
+ // For hsv2rgb, we need to divide by 2 * pi:
1308
+ //
1309
+ float goldenAngleBy2Pi = 0.3819660112501051;
1310
+
1311
+ result.diffuse = hsv2rgb(vec3(float(index) * goldenAngleBy2Pi + 0.1, 1.0, 1.0));
1312
+
1313
+ result.ambient = 0.5 * result.diffuse;
1314
+ }
1315
+ #endif
1316
+
1317
+ #if defined(num_additional_horospheres) && num_additional_horospheres > 0
1318
+ if (ray_hit.object_type == object_type_additional_horosphere) {
1319
+ int index = horosphereCuspIndex[ray_hit.object_index];
1320
+
1321
+ // Similar to geodesic colors.
1322
+ float goldenAngleBy2Pi = 0.3819660112501051;
1323
+
1324
+ result.diffuse = hsv2rgb(vec3(float(index) * goldenAngleBy2Pi + 0.3, 1.0, 1.0));
1325
+
1326
+ result.ambient = 0.5 * result.diffuse;
1327
+ }
1328
+ #endif
1329
+
1330
+ #if num_eyeballs > 0
1331
+ if (ray_hit.object_type == object_type_eyeball) {
1332
+
1333
+ #if eyeball_type == 2
1334
+ vec4 pt = ray_hit.ray.point * eyeballInvEmbeddings[ray_hit.object_index];
1335
+ vec3 d = normalize(pt.yzw);
1336
+
1337
+ vec2 tex_coords = vec2(0.5) + vec2(atan(d.x, -d.z) / 2, asin(d.y)) / radians(180);
1338
+
1339
+ result.diffuse = texture(eyeTexture, tex_coords).xyz;
1340
+ result.ambient = 0.5 * result.diffuse;
1341
+ #else
1342
+ result.diffuse = vec3(0.7, 0.7, 0.7);
1343
+ result.ambient = 0.8 * result.diffuse;
1344
+ #endif
1345
+ }
1346
+ #endif
1347
+
1348
+ #if defined(has_edge_midpoints)
1349
+ if (ray_hit.object_type == object_type_edge_midpoint) {
1350
+ result.diffuse = vec3(0.8,0.8,0.3);
1351
+ result.ambient = 0.5 * result.diffuse;
1352
+ }
1353
+ #endif
1354
+
1355
+ return result;
1356
+ }
1357
+
1358
+ // Compute the value for a valued ray hit (see isColored for explanation)
1359
+ float valueForRayHit(RayHit ray_hit)
1360
+ {
1361
+ if (viewMode == 0) {
1362
+ return ray_hit.weight;
1363
+ } else if (viewMode == 1) {
1364
+ return 0.5 * ray_hit.dist;
1365
+ } else {
1366
+ return float(ray_hit.tet_num);
1367
+ }
1368
+ }
1369
+
1370
+ // Apply lighting for a colored ray hit (see isColored for explanation)
1371
+ vec3 colorForRayHit(RayHit ray_hit)
1372
+ {
1373
+ MaterialParams material = material_params(ray_hit);
1374
+
1375
+ vec4 normal = normalForRayHit(ray_hit);
1376
+
1377
+ vec4 light_position = R13Normalise(ray_hit.light_source);
1378
+
1379
+ // Distance of light source to origin where the eye ray started
1380
+ float light_dist_origin = acosh(-R13Dot(R13Normalise(vec4(1,0,0.7,0)), vec4(1, 0, 0, 0)));
1381
+
1382
+ // Distance of light source to ray hit
1383
+ float unsafe_dist = acosh(-R13Dot(ray_hit.ray.point, light_position));
1384
+
1385
+ // Use triangle inequality to limit distance
1386
+ float dist = clamp(unsafe_dist,
1387
+ ray_hit.dist - light_dist_origin,
1388
+ ray_hit.dist + light_dist_origin);
1389
+
1390
+
1391
+ vec4 light_dir_at_hit = makeUnitTangentVector(
1392
+ - light_position, ray_hit.ray.point);
1393
+
1394
+ float normal_light = clamp(R13Dot(normal, light_dir_at_hit), 0, 1);
1395
+
1396
+ vec4 half_angle = R13Normalise(light_dir_at_hit + ray_hit.ray.dir);
1397
+
1398
+ float blinn_term =
1399
+ normal_light > 0.0
1400
+ ? pow(clamp(R13Dot(half_angle, normal), 0, 1), material.shininess)
1401
+ : 0.0;
1402
+
1403
+ return brightness * (material.ambient
1404
+ + material.diffuse * normal_light
1405
+ + material.specular * blinn_term ) / pow((dist + lightBias) / lightBias, lightFalloff);
1406
+ }
1407
+
1408
+ /// --- Graph-trace code --- ///
1409
+
1410
+ int faceFurthest(vec4 v, int tet_num, int entry_face)
1411
+ {
1412
+ int result = -1;
1413
+ float biggest_amount = 0.0000001;
1414
+ for (int face = 0; face < 4; face++) {
1415
+ if (entry_face != face) {
1416
+ float amount = R13Dot( v, planes[4 * tet_num + face] );
1417
+ if (amount > biggest_amount) {
1418
+ biggest_amount = amount;
1419
+ result = face;
1420
+ }
1421
+ }
1422
+ }
1423
+ return result;
1424
+ }
1425
+
1426
+ void graph_trace(inout RayHit ray)
1427
+ {
1428
+ int entry_face = -1;
1429
+ mat4 tsfm = mat4(1.0);
1430
+
1431
+ for(int i = 0; i < maxSteps; i++) {
1432
+ int face = faceFurthest(ray.ray.point, ray.tet_num, entry_face);
1433
+ if (face == -1) {
1434
+ break;
1435
+ }
1436
+
1437
+ int index = 4 * ray.tet_num + face;
1438
+ entry_face = otherFaceNums[ index ];
1439
+ ray.tet_num = otherTetNums[ index ];
1440
+ ray.weight += weights[ index ];
1441
+ ray.ray.point = ray.ray.point * SO13tsfms[ index ];
1442
+ ray.ray.dir = ray.ray.dir * SO13tsfms[ index ];
1443
+ ray.light_source = ray.light_source * SO13tsfms[ index ];
1444
+ }
1445
+ }
1446
+
1447
+ /// --- Ray init pt and directions code --- ///
1448
+
1449
+ Ray get_ray_eye_space(vec2 xy)
1450
+ {
1451
+ Ray result;
1452
+
1453
+ if (perspectiveType == perspectiveTypeMaterial) {
1454
+ result.point = vec4(1.0,0.0,0.0,0.0);
1455
+ result.dir = R13Normalise(vec4(0.0, 2.0 * xy, -1.0));
1456
+ } else if (perspectiveType == perspectiveTypeIdeal) {
1457
+ // parabolic transformation magic by Saul
1458
+ float r2 = 0.5 * dot(xy, xy);
1459
+ result.point = vec4(r2 + 1.0, xy, r2);
1460
+ result.dir = vec4(r2, xy, r2 - 1.0);
1461
+ } else { // perspectiveTypeHyperIdeal
1462
+ result.point = R13Normalise(vec4(1.0, 2.0 * xy, 0.0));
1463
+ result.dir = vec4(0.0, 0.0, 0.0, -1.0);
1464
+ }
1465
+
1466
+ return result;
1467
+ }
1468
+
1469
+ #if ##finiteTrig##
1470
+ bool
1471
+ leaveVertexNeighborhood(inout RayHit rayHit)
1472
+ {
1473
+ if (vertexSphereRadiusParam <= 1.0001) {
1474
+ return false;
1475
+ }
1476
+
1477
+ float smallest_p = unreachableDistParam;
1478
+
1479
+ // For all vertices
1480
+ for (int vertex = 0; vertex < 4; vertex++) {
1481
+ int index = 4 * rayHit.tet_num + vertex;
1482
+ vec2 params = distParamsForSphereIntersection(
1483
+ rayHit.ray,
1484
+ R13Vertices[index],
1485
+ vertexSphereRadiusParam);
1486
+ if (params.x == unreachableDistParam) {
1487
+ if (params.y < smallest_p) {
1488
+ smallest_p = params.y;
1489
+ rayHit.object_type = object_type_vertex_sphere;
1490
+ rayHit.object_index = vertex;
1491
+ }
1492
+ }
1493
+ }
1494
+
1495
+ if (smallest_p < unreachableDistParam) {
1496
+ rayHit.dist += atanh(smallest_p);
1497
+ rayHit.distWhenLeavingCusp = rayHit.dist;
1498
+ advanceRayByDistParam(rayHit.ray, smallest_p);
1499
+ graph_trace(rayHit);
1500
+ }
1501
+
1502
+ return false;
1503
+ }
1504
+
1505
+ #else
1506
+
1507
+ // Determine whether the ray starts in a horosphere or
1508
+ // Margulis tube.
1509
+ // If yes, move the ray to the point where we exit the
1510
+ // horosphere and set rayHit.object_type to horosphere.
1511
+ //
1512
+ // The result is true if we are inside a horosphere AND
1513
+ // the ray is hitting a peripheral curve on the horosphere.
1514
+ //
1515
+ // For optimization, leaveVertexNeighborhood will also apply a
1516
+ // parabolic transformation to the ray trying to bring the
1517
+ // where we exit the horosphere closer to the entry point.
1518
+ bool
1519
+ leaveVertexNeighborhood(inout RayHit rayHit)
1520
+ {
1521
+ float smallest_p = unreachableDistParam;
1522
+
1523
+ // For all vertices
1524
+ for (int vertex = 0; vertex < 4; vertex++) {
1525
+ int index = 4 * rayHit.tet_num + vertex;
1526
+ // corresponding to complete cusps
1527
+ if (horosphereScales[index] != 0.0) {
1528
+ vec2 params = distParamsForHorosphereIntersection(
1529
+ rayHit.ray, horosphereEqn(index));
1530
+ if (params.x == unreachableDistParam) {
1531
+ // We are in the horosphere
1532
+ if (params.y < smallest_p) {
1533
+ // Remember this
1534
+ smallest_p = params.y;
1535
+ rayHit.object_type = object_type_horosphere_exit;
1536
+ rayHit.object_index = vertex;
1537
+ }
1538
+ }
1539
+ } else if (margulisTubeRadiusParams[index] > 0.50001) {
1540
+ vec2 params = distParamsForTubeIntersection(
1541
+ rayHit.ray,
1542
+ endpointsForMargulisTube(index),
1543
+ margulisTubeRadiusParams[index],
1544
+ 0.0);
1545
+ if (params.x == unreachableDistParam) {
1546
+ if (params.y < smallest_p) {
1547
+ smallest_p = params.y;
1548
+ rayHit.object_type = object_type_margulis_tube_exit;
1549
+ rayHit.object_index = vertex;
1550
+ }
1551
+ }
1552
+ }
1553
+ }
1554
+
1555
+ // We are in a horosphere.
1556
+ if (smallest_p < unreachableDistParam) {
1557
+
1558
+ // Book-keeping and advancing the ray to the exit
1559
+ // point
1560
+ rayHit.dist += smallest_p < 1.0 ? atanh(smallest_p) : 20.0;
1561
+ rayHit.distWhenLeavingCusp = rayHit.dist;
1562
+ advanceRayByDistParam(rayHit.ray, smallest_p);
1563
+
1564
+ int index = 4 * rayHit.tet_num + rayHit.object_index;
1565
+
1566
+ vec2 ml = MLCoordinatesForRayHit(rayHit);
1567
+
1568
+ // Compute the coordinates of exit point in upper half space
1569
+ // such that the cusp is at infinity
1570
+ // Use complex part ignoring height in upper halfspace
1571
+
1572
+ // Check whether we hit peripheral curve
1573
+ if (peripheralCurveForMLCoordinates(ml) > 0) {
1574
+ // Hit peripheral curve
1575
+ return true;
1576
+ }
1577
+
1578
+ // Compute suitable multiple of merdian and longitude translation
1579
+ // bringing the exit point into the fundamental parallelogram
1580
+ // near zero.
1581
+ vec2 c = -round(ml) * inverse(toStandardTorusMatrices[index]);
1582
+
1583
+ mat4 tsfmCuspSpace =
1584
+ (rayHit.object_type == object_type_horosphere_exit)
1585
+ ? parabolicSO13(c)
1586
+ : loxodromicSO13(c);
1587
+
1588
+ // Convert O13 matrix from space where cusp was at infinity
1589
+ // to space of tetrahedron
1590
+ mat4 tsfm =
1591
+ tetToCuspMatrices[index] *
1592
+ tsfmCuspSpace *
1593
+ cuspToTetMatrices[index];
1594
+
1595
+ // And apply transformation to ray.
1596
+ rayHit.light_source = rayHit.light_source * tsfm;
1597
+ rayHit.ray.point = rayHit.ray.point * tsfm;
1598
+ rayHit.ray.dir = R13Normalise( rayHit.ray.dir * tsfm );
1599
+
1600
+ // If we are inside a horosphere, leaveVertexNeighborhood has computed
1601
+ // the point where we leave the horosphere. But that point
1602
+ // might not be inside the current tetrahedron, so fix it.
1603
+ graph_trace(rayHit);
1604
+ }
1605
+
1606
+ return false;
1607
+ }
1608
+
1609
+ #endif
1610
+
1611
+ RayHit computeRayHit(vec2 xy){
1612
+ Ray ray_eye_space = get_ray_eye_space(xy);
1613
+
1614
+ RayHit ray_tet_space;
1615
+ ray_tet_space.ray.point = ray_eye_space.point * currentBoost;
1616
+ ray_tet_space.ray.dir = ray_eye_space.dir * currentBoost;
1617
+ ray_tet_space.dist = 0.0;
1618
+ ray_tet_space.distWhenLeavingCusp = 0.0;
1619
+ ray_tet_space.weight = currentWeight;
1620
+ ray_tet_space.tet_num = currentTetIndex;
1621
+ ray_tet_space.light_source = R13Normalise(lightSourcePosition * currentBoost);
1622
+ ray_tet_space.object_type = object_type_nothing;
1623
+ ray_tet_space.object_index = -1;
1624
+
1625
+ // If using a camera where the ray's do not
1626
+ // all start from a common point, transform ray first
1627
+ // to be inside a tetrahedron.
1628
+ if (perspectiveType != perspectiveTypeMaterial) {
1629
+ graph_trace(ray_tet_space);
1630
+ }
1631
+
1632
+ if (!traceInsideVertexNeighborhood()) {
1633
+ // Check whether we are in a horosphere or Margulis tube and if yes,
1634
+ // whether the ray hit a peripheral curve.
1635
+ if (leaveVertexNeighborhood(ray_tet_space)) {
1636
+ // If we hit a peripheral curve, leaveVertexNeighborhood has
1637
+ // given us the intersection point and we can immediately shade.
1638
+ return ray_tet_space;
1639
+ }
1640
+ }
1641
+
1642
+ // In all other cases, we need to raytrace before we shade.
1643
+ ray_trace(ray_tet_space);
1644
+
1645
+ return ray_tet_space;
1646
+ }
1647
+
1648
+ vec3 sampleNonGeometricTexture(vec2 fragCoord)
1649
+ {
1650
+ vec2 coord = gl_FragCoord.xy - 0.5 * screenResolution.xy;
1651
+ coord.x /= 320.0;
1652
+ coord.y /= -100.0;
1653
+ coord += vec2(0.5, 0.5);
1654
+
1655
+ if (coord.x < 0.002 || coord.x > 0.99 || coord.y < 0.01 || coord.y > 0.99) {
1656
+ return vec3(0.0);
1657
+ }
1658
+
1659
+ return texture(nonGeometricTexture, coord).xyz;
1660
+ }
1661
+
1662
+
1663
+ void main(){
1664
+
1665
+ // Show text "Non-geometric"
1666
+ if (isNonGeometric) {
1667
+ out_FragColor = vec4(sampleNonGeometricTexture(gl_FragCoord.xy), 1.0);
1668
+ return;
1669
+ }
1670
+
1671
+ vec2 xy = (gl_FragCoord.xy - 0.5*screenResolution.xy) /
1672
+ min(screenResolution.x,screenResolution.y);
1673
+ if(multiScreenShot == 1) {
1674
+ // Return multiple 4096x4096 screenshots that can be combined in, e.g. Photoshop.
1675
+ // Here screenResolution is really tileResolution;
1676
+ xy = (xy + tile - 0.5*(numTiles - vec2(1.0,1.0))) / numTiles.x;
1677
+ }
1678
+
1679
+ float min_depth = 1;
1680
+ vec3 total_color = vec3(0);
1681
+ int num_valued_subpixels = 0;
1682
+ float total_value = 0;
1683
+
1684
+ for(int i=0; i<subpixelCount; i++){
1685
+ for(int j=0; j<subpixelCount; j++){
1686
+ vec2 offset =
1687
+ ( vec2(float(1+2*i), float(1+2*j))/float(2*subpixelCount) - vec2(0.5,0.5) )
1688
+ / screenResolution.x / numTiles.x;
1689
+ vec2 scaled_xy = xy + offset;
1690
+ if (perspectiveType != perspectiveTypeHyperideal) {
1691
+ scaled_xy *= viewScale;
1692
+ }
1693
+
1694
+ bool outsideView =
1695
+ perspectiveType == perspectiveTypeHyperideal &&
1696
+ length(scaled_xy) >= 0.5;
1697
+
1698
+ if (outsideView) {
1699
+ total_color += vec3(1.0, 1.0, 1.0);
1700
+ } else {
1701
+ RayHit ray_hit = computeRayHit(scaled_xy);
1702
+ if (ray_hit.object_type != object_type_nothing) {
1703
+ min_depth = min(min_depth, tanh(ray_hit.dist));
1704
+ if (isColored(ray_hit)) {
1705
+ // Accumulate color for colored subpixels.
1706
+ total_color += colorForRayHit(ray_hit);
1707
+ } else {
1708
+ // Accumulate value for valued subpixels.
1709
+ // Count number of valued subpixels so that we can
1710
+ // compute average value.
1711
+ num_valued_subpixels += 1;
1712
+ total_value += valueForRayHit(ray_hit);
1713
+ }
1714
+ }
1715
+ }
1716
+ }
1717
+ }
1718
+
1719
+ if (num_valued_subpixels > 0) {
1720
+ // Average value of valued ray hits.
1721
+ float value = total_value / num_valued_subpixels;
1722
+
1723
+ // Compute gradient and add to total color.
1724
+ //
1725
+ // The contribution of the gradient color is proportional
1726
+ // to the number of valued subsamples for this pixel.
1727
+ total_color += num_valued_subpixels * colorForValue(value);
1728
+ }
1729
+
1730
+ // Divide by total number of subsamples.
1731
+ out_FragColor = vec4(total_color / float(subpixelCount * subpixelCount), 1);
1732
+
1733
+ if (crosshairs) {
1734
+ vec2 coord = gl_FragCoord.xy - floor(0.5 * screenResolution.xy) + vec2(0.5, 0.5);
1735
+ if (abs(coord.x) < 0.1 && abs(coord.y) < 0.1 * screenResolution.x) {
1736
+ out_FragColor.rgb = vec3(1.0) - out_FragColor.rgb;
1737
+ }
1738
+ if (abs(coord.y) < 0.1 && abs(coord.x) < 0.1 * screenResolution.x) {
1739
+ out_FragColor.rgb = vec3(1.0) - out_FragColor.rgb;
1740
+ }
1741
+ }
1742
+
1743
+ gl_FragDepth = min_depth;
1744
+ }