Skip to content

Instantly share code, notes, and snippets.

@stla
Last active December 13, 2018 03:50
Show Gist options
  • Save stla/6892a261bc2c45509cd1482fbeff2f93 to your computer and use it in GitHub Desktop.
Save stla/6892a261bc2c45509cd1482fbeff2f93 to your computer and use it in GitHub Desktop.
Twenty Hopf tori with Asymptote
settings.render = 4;
settings.outformat = "pdf";
import graph3;
import three;
import palette;
size(500,0);
// projection and light --------------------------------------------------------
currentprojection = orthographic(2,0,0);
currentlight = light(gray(0.85), ambient=black, specularfactor=3,
(20,0,0), specular=gray(0.6), viewport=false);
// transformation which reorients and translates -------------------------------
transform3 transReorient(triple axis, triple vector){
triple vX1 = unit(vector);
triple vX2 = unit(axis);
triple vY = unit(cross(vX1,vX2));
triple vZ1 = unit(cross(vX1,vY));
triple vZ2 = unit(cross(vX2,vY));
real[][] M1 =
{{vX1.x, vX1.y, vX1.z},
{vY.x, vY.y, vY.z},
{vZ1.x, vZ1.y, vZ1.z}};
real[][] M2 =
{{vX2.x, vY.x, vZ2.x},
{vX2.y, vY.y, vZ2.y},
{vX2.z, vY.z, vZ2.z}};
real[][] M = transpose(M2*M1);
transform3 T = copy(identity4);
T[0][0] = M[0][0];
T[1][0] = M[1][0];
T[2][0] = M[2][0];
T[0][1] = M[0][1];
T[1][1] = M[1][1];
T[2][1] = M[2][1];
T[0][2] = M[0][2];
T[1][2] = M[1][2];
T[2][2] = M[2][2];
T[0][3] = vector.x;
T[1][3] = vector.y;
T[2][3] = vector.z;
return T;
}
// parameterization of Hopf torus ----------------------------------------------
triple F(pair uv){
real t = uv.x;
real phi = uv.y;
real nlobes = 3;
real A = 0.44;
real p2 = sin(pi/2 - (pi/2-A)*cos(t*nlobes)) * cos(t+A*sin(2*t*nlobes));
real p3 = sin(pi/2 - (pi/2-A)*cos(t*nlobes)) * sin(t+A*sin(2*t*nlobes));
real p1 = cos(pi/2 - (pi/2-A)*cos(t*nlobes));
real yden = sqrt(2*(1+p1));
real y1 = (1+p1)/yden;
real y2 = p2/yden;
real y3 = p3/yden;
real cosphi = cos(phi);
real sinphi = sin(phi);
real x3 = cosphi*y1;
real x4 = sinphi*y1;
real x2 = cosphi*y2 - sinphi*y3;
real x1 = cosphi*y3 + sinphi*y2;
return 0.025 * (x1/(1-x4), x2/(1-x4), x3/(1-x4));
}
// twenty points on the unit sphere --------------------------------------------
real phi = (1 + sqrt(5)) / 2;
real a = 1 / sqrt(3);
real b = a / phi;
real c = a * phi;
triple[] points =
{( a, a, a),
( a, a, -a),
( a, -a, a),
(-a, -a, a),
(-a, a, -a),
(-a, a, a),
( 0, b, -c),
( 0, -b, -c),
( 0, -b, c),
( c, 0, -b),
(-c, 0, -b),
(-c, 0, b),
( b, c, 0),
( b, -c, 0),
(-b, -c, 0),
(-b, c, 0),
( 0, b, c),
( a, -a, -a),
( c, 0, b),
(-a, -a, -a)};
// viridis color palette -------------------------------------------------------
pen[] viridis = {
rgb("440154ff"), rgb("440256ff"), rgb("450457ff"), rgb("450559ff"),
rgb("46075aff"), rgb("46085cff"), rgb("460a5dff"), rgb("460b5eff"),
rgb("470d60ff"), rgb("470e61ff"), rgb("471063ff"), rgb("471164ff"),
rgb("471365ff"), rgb("481467ff"), rgb("481668ff"), rgb("481769ff"),
rgb("48186aff"), rgb("481a6cff"), rgb("481b6dff"), rgb("481c6eff"),
rgb("481d6fff"), rgb("481f70ff"), rgb("482071ff"), rgb("482173ff"),
rgb("482374ff"), rgb("482475ff"), rgb("482576ff"), rgb("482677ff"),
rgb("482878ff"), rgb("482979ff"), rgb("472a7aff"), rgb("472c7aff"),
rgb("472d7bff"), rgb("472e7cff"), rgb("472f7dff"), rgb("46307eff"),
rgb("46327eff"), rgb("46337fff"), rgb("463480ff"), rgb("453581ff"),
rgb("453781ff"), rgb("453882ff"), rgb("443983ff"), rgb("443a83ff"),
rgb("443b84ff"), rgb("433d84ff"), rgb("433e85ff"), rgb("423f85ff"),
rgb("424086ff"), rgb("424186ff"), rgb("414287ff"), rgb("414487ff"),
rgb("404588ff"), rgb("404688ff"), rgb("3f4788ff"), rgb("3f4889ff"),
rgb("3e4989ff"), rgb("3e4a89ff"), rgb("3e4c8aff"), rgb("3d4d8aff"),
rgb("3d4e8aff"), rgb("3c4f8aff"), rgb("3c508bff"), rgb("3b518bff"),
rgb("3b528bff"), rgb("3a538bff"), rgb("3a548cff"), rgb("39558cff"),
rgb("39568cff"), rgb("38588cff"), rgb("38598cff"), rgb("375a8cff"),
rgb("375b8dff"), rgb("365c8dff"), rgb("365d8dff"), rgb("355e8dff"),
rgb("355f8dff"), rgb("34608dff"), rgb("34618dff"), rgb("33628dff"),
rgb("33638dff"), rgb("32648eff"), rgb("32658eff"), rgb("31668eff"),
rgb("31678eff"), rgb("31688eff"), rgb("30698eff"), rgb("306a8eff"),
rgb("2f6b8eff"), rgb("2f6c8eff"), rgb("2e6d8eff"), rgb("2e6e8eff"),
rgb("2e6f8eff"), rgb("2d708eff"), rgb("2d718eff"), rgb("2c718eff"),
rgb("2c728eff"), rgb("2c738eff"), rgb("2b748eff"), rgb("2b758eff"),
rgb("2a768eff"), rgb("2a778eff"), rgb("2a788eff"), rgb("29798eff"),
rgb("297a8eff"), rgb("297b8eff"), rgb("287c8eff"), rgb("287d8eff"),
rgb("277e8eff"), rgb("277f8eff"), rgb("27808eff"), rgb("26818eff"),
rgb("26828eff"), rgb("26828eff"), rgb("25838eff"), rgb("25848eff"),
rgb("25858eff"), rgb("24868eff"), rgb("24878eff"), rgb("23888eff"),
rgb("23898eff"), rgb("238a8dff"), rgb("228b8dff"), rgb("228c8dff"),
rgb("228d8dff"), rgb("218e8dff"), rgb("218f8dff"), rgb("21908dff"),
rgb("21918cff"), rgb("20928cff"), rgb("20928cff"), rgb("20938cff"),
rgb("1f948cff"), rgb("1f958bff"), rgb("1f968bff"), rgb("1f978bff"),
rgb("1f988bff"), rgb("1f998aff"), rgb("1f9a8aff"), rgb("1e9b8aff"),
rgb("1e9c89ff"), rgb("1e9d89ff"), rgb("1f9e89ff"), rgb("1f9f88ff"),
rgb("1fa088ff"), rgb("1fa188ff"), rgb("1fa187ff"), rgb("1fa287ff"),
rgb("20a386ff"), rgb("20a486ff"), rgb("21a585ff"), rgb("21a685ff"),
rgb("22a785ff"), rgb("22a884ff"), rgb("23a983ff"), rgb("24aa83ff"),
rgb("25ab82ff"), rgb("25ac82ff"), rgb("26ad81ff"), rgb("27ad81ff"),
rgb("28ae80ff"), rgb("29af7fff"), rgb("2ab07fff"), rgb("2cb17eff"),
rgb("2db27dff"), rgb("2eb37cff"), rgb("2fb47cff"), rgb("31b57bff"),
rgb("32b67aff"), rgb("34b679ff"), rgb("35b779ff"), rgb("37b878ff"),
rgb("38b977ff"), rgb("3aba76ff"), rgb("3bbb75ff"), rgb("3dbc74ff"),
rgb("3fbc73ff"), rgb("40bd72ff"), rgb("42be71ff"), rgb("44bf70ff"),
rgb("46c06fff"), rgb("48c16eff"), rgb("4ac16dff"), rgb("4cc26cff"),
rgb("4ec36bff"), rgb("50c46aff"), rgb("52c569ff"), rgb("54c568ff"),
rgb("56c667ff"), rgb("58c765ff"), rgb("5ac864ff"), rgb("5cc863ff"),
rgb("5ec962ff"), rgb("60ca60ff"), rgb("63cb5fff"), rgb("65cb5eff"),
rgb("67cc5cff"), rgb("69cd5bff"), rgb("6ccd5aff"), rgb("6ece58ff"),
rgb("70cf57ff"), rgb("73d056ff"), rgb("75d054ff"), rgb("77d153ff"),
rgb("7ad151ff"), rgb("7cd250ff"), rgb("7fd34eff"), rgb("81d34dff"),
rgb("84d44bff"), rgb("86d549ff"), rgb("89d548ff"), rgb("8bd646ff"),
rgb("8ed645ff"), rgb("90d743ff"), rgb("93d741ff"), rgb("95d840ff"),
rgb("98d83eff"), rgb("9bd93cff"), rgb("9dd93bff"), rgb("a0da39ff"),
rgb("a2da37ff"), rgb("a5db36ff"), rgb("a8db34ff"), rgb("aadc32ff"),
rgb("addc30ff"), rgb("b0dd2fff"), rgb("b2dd2dff"), rgb("b5de2bff"),
rgb("b8de29ff"), rgb("bade28ff"), rgb("bddf26ff"), rgb("c0df25ff"),
rgb("c2df23ff"), rgb("c5e021ff"), rgb("c8e020ff"), rgb("cae11fff"),
rgb("cde11dff"), rgb("d0e11cff"), rgb("d2e21bff"), rgb("d5e21aff"),
rgb("d8e219ff"), rgb("dae319ff"), rgb("dde318ff"), rgb("dfe318ff"),
rgb("e2e418ff"), rgb("e5e419ff"), rgb("e7e419ff"), rgb("eae51aff"),
rgb("ece51bff"), rgb("efe51cff"), rgb("f1e51dff"), rgb("f4e61eff"),
rgb("f6e620ff"), rgb("f8e621ff"), rgb("fbe723ff"), rgb("fde725ff") };
// construct the Hopf torus ----------------------------------------------------
surface s = surface(F, (0,0), (2pi,2pi), 65, 65, Spline);
s.colors(palette(s.map(abs), viridis));
// draw the twenty Hopf tori ---------------------------------------------------
picture pic;
for(int i = 0; i < 20; ++i){
transform3 T = transReorient(Z, points[i]);
draw(pic,T*s);
draw(pic,O--points[i]);
draw(pic, extrude(T*circle(c=O, r=0.03, normal=Z), O--cycle),
material(rgb(255,215,0), emissivepen=gray(0.1)));
}
add(rotate(20,X)*rotate(70,Y)*rotate(30,Z)*pic);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment