Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download

All published worksheets from http://sagenb.org

Views: 168698
Image: ubuntu2004

Goal: test Sage's graphics capabilities

This notebooks tests the suitability of using Sage to do the graphics needed by SnapPea. Here is the base code, adapted from Marc's SnapPy.polyviewer
from colorsys import hls_to_rgb import zlib, base64 RR3 = VectorSpace(RDF, 3) def triangle_strip(verts, **kwargs): return sum([polygon3d(verts[i:i+3], **kwargs) for i in range(len(verts) - 2)]) class PoincareTriangle: def __init__(self, vertices, center, **kwargs): self.vertices = vertices self.center = center self.kwargs = kwargs def render_vertex(self, vertex): scale = 1 + sqrt(max(0, 1 - (vertex.norm())^2)) V = (1/scale)*vertex return V def render(self, depth=2): C, V1, V2 = self.vertices M = (1/2)*(V1 + V2) CV1 = V1 - C MV1 = V1 - M CV2 = V2 - C MV2 = V2 - M step = 1.0/depth verts = [] for n in range(depth): verts.append(self.render_vertex(M + MV1*n*step)) verts.append(self.render_vertex(C + CV1*n*step)) verts.append(self.render_vertex(V1)) TS1 = triangle_strip(verts, **self.kwargs) verts = [] for n in range(depth): verts.append(self.render_vertex(C + CV2*n*step)) verts.append(self.render_vertex(M + MV2*n*step)) verts.append(self.render_vertex(V2)) TS2 = triangle_strip(verts, **self.kwargs) return TS1 + TS2 class Face: """ A face of a hyperbolic polyhedron. Instantiate as Face(vertices=[...], closest=[x,y,z], distance=d, hue=h) vertices: list of vertex coordinates (in the Klein model) distance: distance from the origin to the plane closest: coordinates of the point nearest the origin on the plane containing the face hue: (float) hue to use in coloring the face. """ def __init__(self, vertices, distance, closest, hue): self.vertices = [RR3(v) for v in vertices] self.distance = distance self.closest = RR3(closest) K = (1/self.closest.norm())*self.closest self.klein_normal = K self.center = self.closest.norm()^-2 * self.closest self.hue = hue self.kwargs = {"color": hls_to_rgb(self.hue, 0.5, 1.0)} def triangulate(self): Vlist = self.vertices zero = RR3((0,0,0)) N = len(Vlist) triangle_list = [] centroid = (1/N)*sum(Vlist, zero) for i in range(0,N): vertices = [centroid, Vlist[i-1],Vlist[i]] triangle_list.append(PoincareTriangle(vertices, self.center, **self.kwargs)) return triangle_list def poincare_render(self): return sum([T.render() for T in self.triangulate()]) def klein_render(self): return polygon3d(self.vertices, **self.kwargs) class HyperbolicPolyhedron: """ A hyperbolic polyhedron for display in OpenGL, either in the Klein model or the Poincare model. Includes a representation of the sphere at infinity. """ def __init__(self, facedicts): self.faces = [Face(**dict) for dict in facedicts] def render(self, model="Klein"): if model == "Poincare": return sum([face.poincare_render() for face in self.faces]) else: return sum([face.klein_render() for face in self.faces])
raw_data = 'eNrFmt2OHLcRhV9Fd4qBlUGy+Fd+FUEXgSIgBoIEiOTcBHn3fIfsUTSajnZ2yLWttb3qmWGzqk6dc4o979//++1ffv385c9
p7S9vws+1erfSPUfvqcTQnt68/denf3759eOnz7zh/Z/ehZ9TrOYpByvWo6fuT2+42kILHmKJMXisOT+xWvRQPIbOn2ohWfnp6Y1WyKXXXlpnoVb0y1iB+5WWo6VuPYUwVuglpZx6jMl7LaXmY4VWQ2W9EFjdUoumNwf2HmLqnfWd9+cyNhEsWU4sXFtgF35ZIrNXz84eS+NPH0vUELqzYg4tZqs1j62xm+Kt5thaTp5b8X4JhZVL8tpb1Dq1jfdnbbv1ym4I2+O8mGIpngI/ykm7ZCPFnnrL+mEbaWYzRjZbe7bgfKjMSNgP76qNVfk8e/hAeT7+7R+fP33+ouroJr1kEhlLTdQo97l/MhBrK6QhpmxeR6g5t1Ryd+6vkHvVan/9bQIh/OfpzUPYeDiWbfm0aC32GgsYzZZ84tOamwUDtr3wept7A3Cuu7kD5GoWjzXYaaqxgihgpCzVuUgJusCLoVk2hcLVSnLZcItAsnutTYuwvyZ4luyNLgklzTeTm5aIIQPInms+Fk4eck2lscXSvNmxRK0EGSsdlA1MzkYB9p54Y02pNpplrqCLiSx3mqey4UskZKOwhLFL9pbcZlGsVNCfWqilK9rZr9zMK6H3aFTBvwfY7ASi73lkiJ6oMyzVrHpSaLRHbTPpKXdyQFfWJn7I8VuIlccgtkgeZApQ9ERqe2e7occjfxYHWpzf+NzokRqFwlhopBKo4mUFVqYcgKgBppnQ1Cr7JSlkJcUcxw6KU5VcLPLD5+P8OOxRXQmLwNGPhuDOKQDMkivZBfq6aNBc7FSlURRgmC5FFdxgQFBonbTa4D9gSvM4PeEhtWZxXARQ0QWAQF7olmOJCAK46lGdSMhzBfKReHeGGVMrcwFaEv5uCpC8Wb4FRQT6sWjbsROy+QAT9SugkpKCAvI1FrNu8DCNy/KwQt7AOUSCCGQXxgYuRzrpM0ux6WJmB5MHAWyqhbZGqejVbBspYwNz7ZGkxl8gKpi9F8lxntrIjdBjgcXBXZ1XRRoFjuJl8gLKL7TBm8R0PRSJ+bEIrVeqe4TScpaizGj4cEuWEBTQSrYuugZeO5EOkJLtEY3q0wBqZHvIUTvYo4s1ECY+Dh9VP1O2klnGJRYwa6szOaBaXABGwHO0uSMpPS4EXmOf5P1lrBP7CciCEgnbwBqBMuU4CJNeiZ0Ic+XzZWRpCF5Wa0NGRE4C/Wh7SXKlk6FoWmUGQOOQ3gxmIApWSQdAspOwjJMi/WZprlChswAggZnYrg2kB6kTfojWClSnxUPy4TagTDxIkrC9SZS2iKMWsUp30Y+QF3BFikZCA73Rs+xdAbxH24IuOD+RX26dId5bCiJhpAD+VQZg/KkKUe6Cdq1YxMqqRwdDewnlK3A3jJiu8JEeBMgCn+7hdLYuFiSV0m5e9gEwBBocFOlygYHSrFVA4MgmZAeLgb2vZYmtCy+5o1mArcZDxiKbU9PiGavPytKu1DZD+ZJR+woPqkoeulq0K9hJ/OCCFYuWhpYvthQNl/PsiCDwu8gblEG15CCdStkUSJBLutgKJiZIkifNw2nUl39ld/9HXxVMgWM+RKoIfKzQhamAwPMq5D6XpakahEFH8d+cz6gnJpWFDZoY2H3oG0hDq+F5bRwWnYTKftjOKLlD+27fYqs9iC01ag0sl4E43DLuT+dBmWAaOYWT45SW4o4ghKAmpJFC2VTXDeiSRPIO9oGeZanRRDjhy41CmOr6MO0UGyPnbi5xATF9D4fuYPLJKwBaBCIZY/djCYgJrwYJp0KQsV6W4Gb0PuwM+tMZdzGV0fwVWpCOe5xCCTJoizoKZJfakCocgApMbtjUMry4E/XQMB313jpch9KnLInHAz0o8A0/akRikdZBhqCjvGdM2TIrbRBHbEMXU9MKQV5m4DPxNhocOIGFWtpoPi51mC3K3TGG1GMPdEZR4ZiBdUdPR8yEChA1bTWb7IGSdTksPOTYWL2FBTiSI0UeNTux5JS0Imol4/Jz8rYXH0f5ULvmYiU++ZymNeUpqY7sVSc3t8CoIAxr70JlHwSjWKRdURaM8T2mNC82rHLTuQs+N10Mz3q771C0dV1dmddum13L00MklBra7KvCiErcheTwgk1GgpZ1YEWeaTfK/21F40MlXT4O2NXty4xjyliak5GMVz74glYyvVEOtdmcOJLOA1pAuWlBSPyrDhAGIRrRMedf4mjk0DUxBoZ8WnRyADOJ7qLTRsaWfDIDm+4rNeVeJtM3swJg4I3U6XAmlelDQsXO0qkoAzXv7bpZz0uLr+6Ympx1aFHspLJiuWHMXfOjH8OjhlQQKYul0756HIkm5k91NQDQSLnPdy17vw2D5+IAfOv/GGxwEngBzRdsbCKTXiUEmIv8ei7TfzFyMqNCl4wVpTIJ9G9rWx+p7QZd2qCN69PruhwsCNKtuhKmjgfBCSYwHTmVmQc4YmMNmumYIjOzI9YZj4L9cn+2pPRL0TlXE+iIud7WdMUq7DErq/K+eIy5cox6W00GIfoRcgFNTNrTP+oRlU72YLgodp7sxzBe5cbNJh6vhNXaI+WcIwGMbt1lNNKhPfxfCBZBwfh0zTESYGBY0xLag17FLUciG89mdhyHLp3KnozgRTSJ4cs4XGrgB9sCXxakbzOfBYxzwcKwBjFxJ5gEn/d8hWEsDdeUuCrdJwVeOVLYJa8bNH7Dk9OVJzAn4kpZMXhZkCp6SDkToGbiRvPevRxeMEnTlRYqfO2I+4NlXbOBW8zo+iOpLc/UETe2yvquh7KhHY6Gi0Gh9SBnTxseksKlINRjXfj95KEQbEyVcEBRM2yyy0jPRNHHXNdT8tlFdITkkDxz/359qnFaWEg16pi3iNXYRj47NVt5/rDNjK474g1HsksHiLctCxcg2Ux1ptYKYc6wCZXNkiUAS8SHoeGeQMQ1bqN7Vy0bTr3Ts6Xd4J0WH+BueIK8TBlLM/RNs2ZJPels1A0L48dzNH7TGUAbXxUJabKw9AGFMLUwL9sdJVWxIkkwTVjd+7l/evxIdd/J7g4PtmQFb3k0iX1k5rNgPAcvgtKudfqpA5+vRormH9/J4CU+d3WuUB4uzQ7XseOZ9KbH4ysG6JYLsSQ6sWNkJOv0wzHA0oguD830Ckq7HQOJw5w0aBymEcfh91TIma3xk/oWlY2Tyv0PH9fN7V5TyChHvymlOuzt85Tb1Dv60gRp1NHEjKjpaLdznbCRtKuHuRYfzeiaGdplyVa+ankyQ7kmMXgPp61zlRnSOPfFWMxRvk3dBAzYbC7quQsiUO7IKiwB0pOGL1F2fh2S3zBnb/jC0AZvud2T6XRKRTM9VTh0q4/jSpMdgGD7UXBepcvJgix6uuKg/nBtd3TM+leLl7+AuvyAZPejhXdDhxASDbFUkTq2Y0tZ53lVRrYjdPNQFwHsTemWFSa4flNdLnz/te/ShrOkRppq7MRyS51xwDXqS1aX87Xbi7fXjrPCRgIDzlqHysD+ODp69mKpZ5+fp4r3XDtxuri2Ns6saF0LxzNVrIWgZYkC2ATYd9euXO71P7f98lw+b+O0s+DPQvr6pOU6z/WsIKcX03JFTk/nvkvgu/syfWV/NmT1DkTms2uLKDvO9+76+LvnUfp/IHmT0B/nM5XFfK627TJKXz2nd0L3VbO6CrOXMccKk9+Opvcl9If5bGU7l74AJK+D0heU5OR7zncJ1DNc2v7o3r9JVTuD1FlO7dUV/4F8xuu2//0Vf5k1HlbG+7TphV2/nM9FR7q7HCv+6V779GOE1vWMLqv9Eg+vMMYdGX250tc/uucX/exm93QXjf7uc9NLMbbCoq+O0NWJ6cOH/wLEiAXg' m016_data, borromean_data = eval(zlib.decompress(base64.b64decode(raw_data))) ///
show(HyperbolicPolyhedron(m016_data).render(), frame=False)
show(HyperbolicPolyhedron(borromean_data).render(), frame=False)
#It has some trouble this, at least over a network. Should consider using parametric_plot3d for the sides, as that might produce better results S = HyperbolicPolyhedron(borromean_data).render(model="Poincare"); show(S, frame=False)
#Note, I changed the depth parameter on this to 6 to get a pretty picture. Tachyon is actually a full-featured ray-tracer so one could make the picture look a lot nicer if one wanted. R = HyperbolicPolyhedron(m016_data).render(model="Poincare"); R.show(viewer='tachyon')