{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "require.undef(\"nbextensions/vpython_libraries/glow.min\");" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "require.undef(\"nbextensions/vpython_libraries/glowcomm\");" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "require.undef(\"nbextensions/vpython_libraries/jquery-ui.custom.min\");" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "require([\"nbextensions/vpython_libraries/glow.min\"], function(){console.log(\"GLOW LOADED\");})" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "require([\"nbextensions/vpython_libraries/glowcomm\"], function(){console.log(\"GLOWCOMM LOADED\");})" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "require([\"nbextensions/vpython_libraries/jquery-ui.custom.min\"], function(){console.log(\"JQUERY LOADED\");})" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "window.__context = { glowscript_container: $(\"#glowscript\").removeAttr(\"id\")}" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from vpython import *\n", "\n", "# Bruce Sherwood\n", "\n", "# A surreal scene that illustrates many of the features of GlowScript\n", "\n", "# Add instructions below the display\n", "s = \"Fly through the scene:
\"\n", "s += \" drag the mouse or your finger above or below the center of the scene to move forward or backward;
\"\n", "s += \" drag the mouse or your finger right or left to turn your direction of motion.
\"\n", "s += \"(Normal GlowScript rotate and zoom are turned off in this program.)\"\n", "scene.caption = s\n", "\n", "ycenter = 2\n", "scene.width = 800\n", "scene.height = 400\n", "scene.range = 12\n", "scene.center = vector(0,ycenter,0)\n", "scene.userspin = False\n", "scene.userzoom = False\n", "scene.background = color.gray(0.5)\n", "scene.ambient = color.gray(0.4)\n", "\n", "def hourminute():\n", " #GlowScript JavaScript date machinery\n", " #d = Date()\n", " #hour = d.getHours() % 12\n", " #minute = d.getMinutes()\n", " now = time.localtime(time.time())\n", " hour = now[3] % 12\n", " minute = now[4]\n", " return (hour, minute)\n", "\n", "class analog_clock:\n", " def __init__(self, pos, radius, axis):\n", " self.pos = pos\n", " self.axis = axis\n", " self.radius = radius\n", " self.spheres = []\n", " self.hour = 0\n", " self.minute = -1\n", " for n in range(12):\n", " sp = sphere(pos=pos+(radius*scene.up).rotate(angle=-2*pi*n/12, axis=axis),\n", " size=(2*radius/20)*vector(1,1,1),\n", " color=color.hsv_to_rgb(vector(n/12,1,1)) )\n", " self.spheres.append(sp)\n", " self.hand = arrow(pos=self.pos, axis=0.95*radius*scene.up,\n", " shaftwidth=radius/10, color=color.cyan)\n", " self.update()\n", " \n", " def update(self):\n", " hour, minute = hourminute()\n", " hour = hour % 12\n", " if self.hour == hour and self.minute == minute: return\n", " self.hand.axis = (0.95*self.radius*scene.up).rotate(\n", " axis=vector(0,0,1), angle=-2*pi*minute/60)\n", " self.spheres[self.hour].size = (2*self.radius/20)*vector(1,1,1)\n", " self.spheres[hour].size = (2*self.radius/10)*vector(1,1,1)\n", " self.hour = hour\n", " self.minute = minute\n", "\n", "grey = color.gray(0.8)\n", "Nslabs = 8\n", "R = 10\n", "w = 5\n", "d = 0.5\n", "h = 5\n", "photocenter = 0.15*w\n", "\n", "# The floor, central post, and ball atop the post\n", "floor = box(pos=vector(0,-0.1,0),size=vector(.2,24,24), axis=vector(0,1,0), texture=textures.wood)\n", "pole= cylinder(pos=vector(0,0,0),axis=vector(0,1,0), size=vector(h,0.4,0.4), color=color.red)\n", "sphere(pos=vector(0,h,0), size=vector(1,1,1), color=color.red)\n", "\n", "# Set up the gray slabs, including a portal\n", "for i in range(Nslabs):\n", " theta = i*2*pi/Nslabs\n", " c = cos(theta)\n", " s = sin(theta)\n", " xc = R*c\n", " zc = R*s\n", " if i == 2: # Make a portal\n", " box(pos=vector(-3.*w/8.,0.75*h/2.,R),\n", " size=vector(0.5*w/2,0.75*h,d), color=grey)\n", " box(pos=vector(3.*w/8.0,0.75*h/2.,R),\n", " size=vector(0.5*w/2,0.75*h,d), color=grey)\n", " box(pos=vector(0,0.85*h,R),\n", " size=vector(w,0.3*h,d), color=grey)\n", " else:\n", " slab = box(pos=vector(R*c, h/2., R*s), axis=vector(c,0,s),\n", " size=vector(d,h,w), color=grey)\n", " if i != 6:\n", " T = textures.flower\n", " if (i == 7 or i == 4): T = textures.rug\n", " box(pos=slab.pos,\n", " size=vec(1.1*d,0.9*4*photocenter,0.9*4*photocenter), axis=vec(c,0,s),\n", " texture=T)\n", "\n", "entry = text(pos=vector(0,4.4,R+d/2), text='Surreal\\nStonehenge', align='center',\n", " depth=0.3, height=0.5)\n", " \n", "B = text(pos=vector(0.4*R,0,-1*R), text='B', height=2, align='center', font='serif',\n", " color=color.magenta, depth=1)\n", "\n", "gh = 1\n", "ga = 1\n", "gr = 0.05\n", "rgear = 0.7\n", "tgear = ga/5 # gear thickness\n", "support = extrusion(pos=vector(7,gh/2,10), path=[vector(0,0,0), vector(0,gh,0), vector(0,gh,ga), vector(0,0,ga)],\n", " shape=shapes.circle(radius=gr), color=vector(1,.7,0))\n", "support.clone(pos=vector(7+2*rgear,gh/2,10))\n", "gear1 = extrusion(pos=support.pos+vector(0,gh/2,0), path=[vector(0,0,-tgear/2), vector(0,0,tgear/2)],\n", " shape=shapes.gear(radius=rgear), color=color.gray(0.85), texture=textures.metal)\n", "gear2 = gear1.clone(pos=gear1.pos+vector(2*rgear,0,0))\n", "gear1.rotate(angle=-0.4*2*pi/20, axis=vector(0,0,1)) # default is 20 teeth\n", "\n", "# Decorate back slab with a wood box and a clock\n", "box(pos=vector(0,h/2.,-R+d/2+0.1), size=vector(w/2.,w/2.,0.2), texture=textures.wood)\n", "clock = analog_clock(vector(0,h/2.,-R+d/2+0.2+0.2*h/10), 0.2*w, vector(0,0,1))\n", "\n", "# Draw guy wires from the top of the central post\n", "Nwires = 32\n", "for i in range(Nwires):\n", " theta = i*2*pi/Nwires\n", " L = vector(R * cos(theta), -h - 0.1, R * sin(theta))\n", " cylinder(pos=vector(0,h,0), axis=L, size=vector(mag(L),.04,.04), color=vector(1,0.7,0))\n", "\n", "# Display a pyramid\n", "pyramid(pos=vector(-4,0,-5), size=vector(2,2,2), axis=vector(0,3,0), color=vector(0,.5,0), texture=textures.rough)\n", "\n", "# Display smoke rings rising out of a black tube\n", "smoke = []\n", "Nrings = 20\n", "x0, y0, z0 = -5, 1.5, -2\n", "r0 = 0.075\n", "spacing = 0.2\n", "thick = r0/3\n", "dr = 0.0075\n", "dthick = thick/Nrings\n", "gray = 1\n", "cylinder(pos=vector(x0,0,z0), axis=vector(0,y0+r0,0), radius=1.5*(r0+thick), color=color.black)\n", "\n", "# Create the smoke rings\n", "for i in range(Nrings):\n", " smoke.append(ring(pos=vector(x0,y0+spacing*i,z0), axis=vector(0,1,0),\n", " radius=r0+dr*i, thickness=thick-dthick*i))\n", "y = 0\n", "dy = spacing/20\n", "top = Nrings-1\n", "\n", "# Log rolls back and forth between two stops\n", "rlog = 1\n", "wide = 4\n", "zpos = 2\n", "zface = 5\n", "tlogend = 0.2\n", "v0 = 0.3\n", "v = v0\n", "omega = -v0 / rlog\n", "theta = 0\n", "dt = 0.1\n", "tstop = 0.3\n", "logcyl = cylinder(pos=vector(-wide, rlog, zpos), size=vector(zface - zpos, 2, 2),\n", " axis=vector(0, 0, 1), texture=textures.granite)\n", "leftstop = box(pos=vector(-wide-rlog-tstop/2,0.6*rlog,(zpos+zface)/2),\n", " size=vector(tstop, 1.2*rlog, (zface-zpos)), color=color.red, emissive=True)\n", "rightstop = box(pos=vector(wide+rlog+tstop/2,0.6*rlog,(zpos+zface)/2),\n", " size=vector(tstop, 1.2*rlog, (zface-zpos)), color=color.red, emissive=True)\n", "\n", "# Run a ball up and down the pole\n", "y1 = 0.2*h\n", "y2 = 0.7*h\n", "rball = 0.4\n", "Dband = 1.3 * pole.size.y\n", "cylinder(pos=vector(0,y1-0.9*rball,0), axis=vector(0,1,0), size=vector(0.1,Dband,Dband), color=color.green)\n", "cylinder(pos=vector(0,y2+0.9*rball,0), axis=vector(0,1,0), size=vector(0.1,Dband,Dband), color=color.green)\n", "vball0 = 0.3*v0\n", "vball = vball0\n", "ballangle = 0.05*pi\n", "ball = []\n", "ball.append(sphere(pos=vector(0,0,0), size=2*rball*vector(1,1,1), color=color.blue))\n", "for nn in range(4):\n", " cc = cone(pos=vector(0,0,0)+vector(0.8*rball,0,0), axis=vector(3*rball,0,0),\n", " size=rball*vector(3,1,1), color=color.yellow)\n", " cc.rotate(angle=0.5*nn*pi, axis=vector(0,1,0), origin=vector(0,0,0))\n", " ball.append(cc)\n", "ball = compound(ball)\n", "ball.pos = vector(0,y1,0)\n", "\n", "# A table with a mass-spring object sliding on it\n", "table = cone(pos=vector(0.4*R, h/4, -.3*R), size=vector(h/4, 0.6 * R, 0.6 * R), \n", " axis=vector(0, -1, 0), texture={'file':textures.wood_old, 'turn':1})\n", "tabletop = table.pos\n", "rspring = 0.02 * h\n", "Lspring = .15 * R\n", "Lspring0 = .1 * R\n", "hmass = 4 * rspring\n", "post = cylinder(pos=tabletop, axis=vector(0, 1, 0), size=vector(2 * hmass, .4, .4), color=color.gray(.6))\n", "spring = helix(pos=post.pos + vector(0, hmass/2, 0), size=vector(Lspring, 2 * rspring, 2 * rspring),\n", " color=color.orange, thickness=rspring)\n", "mass = cylinder(pos=post.pos + vector(Lspring, 0, 0), axis=vector(0, 1, 0),\n", " size=vector(hmass, .04 * R, .04 * R), color=color.orange)\n", "mass.p = vector(10, 0, 5)\n", "mass.m = 1\n", "kspring = 200\n", "deltat = .01\n", "\n", "# Display an ellipsoid\n", "Rcloud = 0.8*R\n", "omegacloud =3*v0/Rcloud\n", "cloud = sphere(pos=vector(0,0.7*h,-Rcloud), size=vector(5,2,2),\n", " color=color.green, opacity=0.3)\n", "\n", "rhairs = 0.025 # half-length of crosshairs\n", "dhairs = 2 # how far away the crosshairs are\n", "maxcosine = dhairs/sqrt(rhairs**2+dhairs**2) # if ray inside crosshairs, don't move\n", "haircolor = color.black\n", "roam = 0\n", "\n", "scene.visible = False\n", "scene.waitfor(\"textures\")\n", "scene.visible = True\n", "\n", "roam = False\n", "\n", "def setroam(evt):\n", " global roam\n", " roam = not roam\n", "\n", "scene.bind(\"mousedown mouseup\", setroam)\n", "\n", "hue = 0\n", "dhue = 0.01\n", "gangle = 0.03 # incremental rotation of the gears\n", "\n", "while True:\n", " rate(30)\n", "\n", " # If in roaming mode, change center and forward according to mouse position\n", " if roam:\n", " ray = scene.mouse.ray\n", " if abs(ray.dot(scene.forward)) < maxcosine: # do something only if outside crosshairs\n", " newray = norm(vector(ray.x, 0, ray.z))\n", " angle = asin(scene.forward.cross(newray).dot(scene.up))\n", " scene.camera.rotate(angle=angle/30, axis=scene.up)\n", " scene.camera.pos = scene.camera.pos + (ray.y/2)*norm(scene.camera.axis)\n", " \n", " hue += dhue\n", " entry.color = color.hsv_to_rgb(vector(hue,1,1))\n", " \n", " B.rotate(angle=0.05, axis=scene.up)\n", " \n", " gear1.rotate(angle=gangle, axis=vector(0,0,1))\n", " gear2.rotate(angle=-gangle, axis=vector(0,0,1))\n", "\n", " # Roll the log\n", " theta = theta + omega*dt\n", " logcyl.pos.x = logcyl.pos.x+v*dt\n", " logcyl.rotate(angle=omega*dt, axis=vector(0,0,1))\n", " if logcyl.pos.x >= wide:\n", " v = -v0\n", " omega = -v/rlog\n", " if rightstop.color.equals(color.red):\n", " rightstop.color = color.cyan\n", " else:\n", " rightstop.color = color.red\n", " if logcyl.pos.x <= -wide:\n", " v = +v0\n", " omega = -v/rlog\n", " if leftstop.color.equals(color.red):\n", " leftstop.color = color.cyan\n", " else:\n", " leftstop.color = color.red\n", "\n", " # Move the cloud\n", " cloud.rotate(angle=omegacloud*dt, origin=vector(0,0,0), axis=vector(0,1,0))\n", "\n", " # Run the ball up and down\n", " ball.pos.y = ball.pos.y+vball*dt\n", " ball.rotate(angle=ballangle, axis=vector(0,1,0), origin=vector(0,0,0))\n", " if ball.pos.y >= y2:\n", " vball = -vball0\n", " ballangle = -ballangle\n", " if ball.pos.y <= y1:\n", " vball = +vball0\n", " ballangle = -ballangle\n", "\n", " # Move the smoke rings\n", " for i in range(Nrings):\n", " # Raise the smoke rings\n", " smoke[i].pos = smoke[i].pos+vector(0,dy,0)\n", " smoke[i].radius = smoke[i].radius+(dr/spacing)*dy\n", " smoke[i].thickness = smoke[i].thickness - (dthick/spacing)*dy\n", " y = y+dy\n", " if y >= spacing:\n", " # Move top ring to the bottom\n", " y = 0\n", " smoke[top].pos = vector(x0, y0, z0)\n", " smoke[top].radius = r0\n", " smoke[top].thickness = thick\n", " top = top-1\n", " if top < 0:\n", " top = Nrings-1\n", " \n", " # Update the mass-spring motion\n", " F = -kspring * (spring.size.x - Lspring0) * spring.axis.norm()\n", " mass.p = mass.p + F * deltat\n", " mass.pos = mass.pos + (mass.p / mass.m) * deltat\n", " spring.axis = mass.pos + vector(0, hmass / 2, 0) - spring.pos\n", "\n", " # Update the analog clock on the back slab\n", " clock.update()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "VPython", "language": "python", "name": "vpython" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.0" } }, "nbformat": 4, "nbformat_minor": 1 }