From 2302c8a248e866fbf4f6083bfb3e2f43a9b62b04 Mon Sep 17 00:00:00 2001 From: jcoady Date: Sat, 16 Mar 2024 06:07:30 -0700 Subject: [PATCH] Added some webvpython demos --- Demos/CORS.ipynb | 1 + Demos/Conch.ipynb | 1 + Demos/ElectricMotor.ipynb | 1 + Demos_no_notebook/CORS.py | 17 ++ Demos_no_notebook/Conch.py | 40 ++++ Demos_no_notebook/ElectricMotor.py | 360 +++++++++++++++++++++++++++++ setup.py | 2 +- 7 files changed, 421 insertions(+), 1 deletion(-) create mode 100644 Demos/CORS.ipynb create mode 100644 Demos/Conch.ipynb create mode 100644 Demos/ElectricMotor.ipynb create mode 100644 Demos_no_notebook/CORS.py create mode 100644 Demos_no_notebook/Conch.py create mode 100644 Demos_no_notebook/ElectricMotor.py diff --git a/Demos/CORS.ipynb b/Demos/CORS.ipynb new file mode 100644 index 0000000..4936084 --- /dev/null +++ b/Demos/CORS.ipynb @@ -0,0 +1 @@ +{"metadata":{"kernelspec":{"display_name":"Python 3 (ipykernel)","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.12.2","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":5,"nbformat":4,"cells":[{"id":"1ce368bf-81e1-4832-8f46-605e44d885f6","cell_type":"code","source":"from vpython import *\nscene = canvas() # This is needed in Jupyter notebook and lab to make programs easily rerunnable\nscene.range = 1\nscene.forward = vector(-1,-.5,-1)\nbox(texture=\"https://s3.amazonaws.com/glowscript/textures/flower_texture.jpg\")\n\ns = 'This illustrates the use of an image from another web site as a texture.\\n'\ns += 'This is an example of CORS, \"Cross-Origin Resource Sharing\".\\n'\nscene.caption = s\n\nscene.append_to_caption(\"\"\"\nTo rotate \"camera\", drag with right button or Ctrl-drag.\nTo zoom, drag with middle button or Alt/Option depressed, or use scroll wheel.\n On a two-button mouse, middle is left + right.\nTo pan left/right and up/down, Shift-drag.\nTouch screen: pinch/extend to zoom, swipe or two-finger rotate.\"\"\")","metadata":{"trusted":false},"outputs":[{"metadata":{},"output_type":"display_data","data":{"text/html":"
","text/plain":""}},{"metadata":{},"output_type":"display_data","data":{"application/javascript":"if (typeof Jupyter !== \"undefined\") { window.__context = { glowscript_container: $(\"#glowscript\").removeAttr(\"id\")};}else{ element.textContent = ' ';}","text/plain":""}},{"metadata":{},"output_type":"display_data","data":{"text/plain":"","text/html":"
"}},{"data":{"text/plain":"","application/javascript":"if (typeof Jupyter !== \"undefined\") { window.__context = { glowscript_container: $(\"#glowscript\").removeAttr(\"id\")};}else{ element.textContent = ' ';}"},"metadata":{},"output_type":"display_data"}],"execution_count":1},{"id":"eeec5bc6-e4c1-4ca8-81af-d8a97c6ab412","cell_type":"code","source":"","metadata":{"trusted":false},"outputs":[],"execution_count":null}]} \ No newline at end of file diff --git a/Demos/Conch.ipynb b/Demos/Conch.ipynb new file mode 100644 index 0000000..16ab585 --- /dev/null +++ b/Demos/Conch.ipynb @@ -0,0 +1 @@ +{"metadata":{"kernelspec":{"display_name":"Python 3 (ipykernel)","language":"python","name":"python3"},"language_info":{"file_extension":".py","nbconvert_exporter":"python","codemirror_mode":{"name":"ipython","version":3},"name":"python","pygments_lexer":"ipython3","mimetype":"text/x-python","version":"3.12.1"}},"nbformat_minor":5,"nbformat":4,"cells":[{"id":"9c2f0c0c-4898-4122-9c2a-f0f77ea52094","cell_type":"code","source":"from vpython import *\nscene = canvas() # This is needed in Jupyter notebook and lab to make programs easily rerunnable\n# Kadir Haldenbilen, Feb. 2011\n\nscene.height = scene.width = 600\nscene.background = color.gray(0.7)\nscene.range = 3\nscene.ambient = 0.5*color.white\n\nscene.caption = \"\"\"To rotate \"camera\", drag with right button or Ctrl-drag.\nTo zoom, drag with middle button or Alt/Option depressed, or use scroll wheel.\n On a two-button mouse, middle is left + right.\nTo pan left/right and up/down, Shift-drag.\nTouch screen: pinch/extend to zoom, swipe or two-finger rotate.\"\"\"\n\ndef spiral(nloop=1, tightness=1.0, dir=1, scale=1):\n spr = []\n scale = []\n clrs = []\n zd = 0.01\n for t in range(1, 1024*nloop, 16):\n t *= 0.01\n x = tightness/10 * t * cos(t)*dir\n y = tightness/10 * t * sin(t)\n sc = sqrt(x*x+y*y)\n z = t/7\n spr.append(vector(x,y,z))\n clr = vector(z*cos(t), abs(sin(t)), abs(cos(t*2))).norm()\n clrs.append(clr)\n scale.append(sc)\n return spr, scale, clrs\n\npath, scale, clrs = spiral(nloop=2, tightness=0.8)\nelps = shapes.circle(radius=0.69, thickness=0.01)\n\nee = extrusion(shape=elps, path=path, color=clrs, scale=scale, texture=textures.rock)\nee.rotate(angle=pi/2)\nscene.center = ee.pos-vec(0,.5,0)\n\n","metadata":{"trusted":false},"outputs":[{"data":{"text/html":"
","text/plain":""},"metadata":{},"output_type":"display_data"},{"metadata":{},"data":{"application/javascript":"if (typeof Jupyter !== \"undefined\") { window.__context = { glowscript_container: $(\"#glowscript\").removeAttr(\"id\")};}else{ element.textContent = ' ';}","text/plain":""},"output_type":"display_data"},{"data":{"text/plain":"","text/html":"
"},"metadata":{},"output_type":"display_data"},{"metadata":{},"output_type":"display_data","data":{"text/plain":"","application/javascript":"if (typeof Jupyter !== \"undefined\") { window.__context = { glowscript_container: $(\"#glowscript\").removeAttr(\"id\")};}else{ element.textContent = ' ';}"}}],"execution_count":1},{"id":"d01c51ea-d6a6-4d7f-aac1-de28cf657c72","cell_type":"code","source":"","metadata":{"trusted":false},"outputs":[],"execution_count":null}]} \ No newline at end of file diff --git a/Demos/ElectricMotor.ipynb b/Demos/ElectricMotor.ipynb new file mode 100644 index 0000000..85dca85 --- /dev/null +++ b/Demos/ElectricMotor.ipynb @@ -0,0 +1 @@ +{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3 (ipykernel)","language":"python"},"language_info":{"name":"python","version":"3.12.2","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":5,"nbformat":4,"cells":[{"id":"b0ff27bb-79db-4eb3-aa8c-4668263e631a","cell_type":"code","source":"from vpython import *\nscene = canvas() # This is needed in Jupyter notebook and lab to make programs easily rerunnable\n# Kadir Haldenbilen, February 2011\n# Converted to Web VPython by Bruce Sherwood, May 2022\n\nscene.width = 1024\nscene.height = 768\nscene.center = vec(-2,0,0)\nscene.range = 7\n\nmotor = [] # elements that rotate\ncl = 2\nns = 24\n\ndef makearc(center=[0,0], radius=1, angle1=2*pi-pi/4, angle2=2*pi+pi/4, ccw=True):\n # Specify angle1 and angle2 as positive numbers, with angle2 > angle1\n if angle2 < angle1:\n raise Exception(\"Both angles must be positive, with angle2 > angle1\") \n n = 20\n dtheta = abs(angle2-angle1)/n\n ret = []\n for i in range(n+1):\n if ccw:\n #print(center, angle1, angle2, radius, ccw)\n ret.append([center[0]+radius*cos(angle1+i*dtheta), center[1]+radius*sin(angle1+i*dtheta)])\n else:\n #print(center, angle1, angle2, radius, ccw)\n ret.append([center[0]+radius*cos(angle2-i*dtheta), center[1]+radius*sin(angle2-i*dtheta)])\n return ret\n\ndef rotatepoints(points=[[1,0],[0,1]], angle=0, origin=vec(0,0,0)):\n s = sphere(visible=False)\n ret = []\n for p in points:\n s.pos = vec(p[0],p[1],0)\n s.rotate(angle=angle, axis=vec(0,0,1), origin=origin)\n ret.append([s.pos.x,s.pos.y])\n return ret \n\n#=====================================================================\n# Create contactor\n\np2 = makearc(center=[0,0], radius=0.5, angle1=0, angle2=pi/20, ccw=False)\np1 = makearc(center=[0,0], radius=1.2, angle1=0, angle2=pi/15, ccw=True)\np = p1+p2+[p1[0]]\nc = extrusion(path=[vec(0,0,0),vec(2,0,0)], shape=p, color=vec(1,0.5,0.3))\ncont = [c]\nfor i in range(1,24):\n con = c.clone()\n con.rotate(angle=i*2*pi/24, axis=vec(-1,0,0), origin=vec(0,0,0))\n cont.append(con)\nmotor.append(compound(cont))\n#==========================================================================\n# Create contactor soldering tips\n\np1 = makearc(center=[0,0], radius=1.4, angle1=2*pi-0.5*pi/24, angle2=2*pi+0.4*pi/24, ccw=True)\np2 = makearc(center=[0,0], radius=0.7, angle1=2*pi-0.5*pi/30, angle2=2*pi+0.4*pi/30, ccw=False)\np = p1+p2+[p1[0]]\nc = extrusion(path=[vec(-0.4,0,0),vec(0,0,0)], shape=p, color=vec(1,0.5,0.3))\ns = sphere(pos=vec(-0.2,0,1.195), radius=0.1, shininess=1)\ncont = [c]\nballs = []\nfor i in range(23):\n con = c.clone()\n con.rotate(angle=(i+1)*2*pi/24, axis=vec(1,0,0), origin=vec(0,0,0))\n cont.append(con)\n con = s.clone()\n con.rotate(angle=(i+1)*2*pi/24, axis=vec(1,0,0), origin=vec(0,0,0))\n balls.append(con)\n \nmotor.append(compound(cont))\nmotor.append(compound(balls))\n#=========================================================================\n# Add shaft insulator material\n# Define a circular ring of thickness=0.05\nsc = shapes.circle(radius=0.53, thickness=0.05)\n# Extrude the ring to get a thin hollow cylinder insulator over the shaft\nsce = extrusion(path=[vec(-7,0,0),vec(2.5,0,0)], shape=sc, color=vec(0.8,0,0),\n emissive=True) # plastic\n\n# The Rotor Shaft, defined by a simple cylinder\nshaft = cylinder(pos=vec(3.5,0,0), axis=vec(-11.25,0,0), radius=0.495, color=color.gray(.6), texture=textures.metal)\n\n# Add a piece of gear at one end of the shaft\n# Use the gear shape to define the shape, note radius, addendum, dedendum sizes\ngr = shapes.gear(n=9, radius=0.455, addendum=0.04, dedendum=0.06, fradius=0.01)\n# Extrude the gear shape appending it to the shaft end\ngre = extrusion(path=[vec(3.5,0,0),vec(5,0,0)], shape=gr, color=color.gray(.6),\n texture=textures.metal)\n\nmotor.append(gre)\n#for o in scene.objects: o.visible = False\n#==========================================================================\n# Define Rotor Core\n# Normally the core should have been built of many very thin sheets\n# For performance reasons, a single block is built\n# First define the outer circle\n\nr0 = 0.495 # radius of shaft\nr1 = 1.3 # radius of disk\nr2 = 2.7 # radius of inner portion of top of the T\nr3 = 3 # radius of outer portion of top of the T\ntheta = pi/12 # angle between Ts\nd = 0.25*theta # half angle width of upright of T\ndlt = 0.05\nthk = 5.04\n\np1 = makearc(center=[0,0], radius=r1, angle1=2*pi-pi/12+d, angle2=2*pi+pi/12-d, ccw=True)\nstart = r1*vec(cos(-pi/12+d), sin(-pi/12+d),0)\n# From middle of bottom of T base to middle of top of T upright:\nmiddledir = vec(cos(pi/12),sin(pi/12), 0)\nperp = middledir.rotate(angle=pi/2, axis=vec(0,0,1))\np1end = vec(p1[-1][0], p1[-1][1],0)\nendpt1 = p1end+(r2-r1)*middledir # top right of T upright\nnextstart = start.rotate(angle=pi/6, axis=vec(0,0,1))\nendpt2 = nextstart + (r2-r1)*middledir\na = atan(endpt1.y/endpt1.x)\np2 = makearc(center=[0,0], radius=r2, angle1=0.3*a, angle2=a, ccw=False)\np1.extend(p2)\np3 = makearc(center=[0,0], radius=r3, angle1=0.3*a, angle2=1.5*a+2*d, ccw=True)\np1.extend(p3)\nb = atan(endpt2.y/endpt2.x)\np4 = makearc(center=[0,0], radius=r2, angle1=b, angle2=1.5*a+2*d, ccw=False)\np1.extend(p4)\n\npc = p1.copy()\nfor i in range(1,12):\n p = rotatepoints(p1, angle=i*pi/6)\n pc.extend(p)\npc.append(pc[0])\n\nex = extrusion(path=[vec(-6,0,0), vec(-6+thk,0,0)], shape=[pc, shapes.circle(radius=r0)] , color=color.gray(0.7))\nmotor.append(ex)\n\n#==========================================================================\n# Do the core wire windings\nx = -3.5\nn = 20\nL = 1.3\nthk = L/50\ncon = []\nfor i in range(n):\n r = r1+i*thk*2.5\n inner = shapes.rectangle(width=5.2, height=.35, roundness=0.4)\n outer = shapes.rectangle(width=5.3+i*0.7/n, height=0.4+i*0.6/n, roundness=0.4)\n p = [vec(x,r*sin(pi/12),r*cos(pi/12)), vec(x,(r+thk)*sin(pi/12),(r+thk)*cos(pi/12))]\n ex = extrusion(path=p, shape=[outer,inner], color=vec(.7,.5,.15))\n con.append(ex)\nex = compound(con)\ncon = [ex]\n\nfor i in range(1,12):\n c = ex.clone()\n c.rotate(angle=i*pi/6, axis=vec(1,0,0), origin=vec(0,0,0))\n con.append(c)\n\nmotor.append(compound(con))\n\n#==========================================================================\n# Connect contactor surfaces to windings with cables\npos = vec(-1.3,1.1,0)\nc0 = cylinder(pos=pos, axis=vec(-0.25,1.2,0.25)-pos, radius=0.05, color=color.blue)\ncon = [c0]\nfor i in range(1,24):\n c = c0.clone()\n c.rotate(angle=i*pi/6, axis=vec(1,0,0), origin=vec(c0.pos.x,0,0))\n con.append(c)\nmotor.append(compound(con))\n\n#==========================================================================\n# Create Brushes\n# From a rectangular cross section, subtract rotor contactor circle, leaving us two\n# brushes on each sides of the contactor, with circular profile\n#br = shapes.rectangle(width=5, height=0.4)\nbr = makearc(center=[0,0], radius=1.21, angle1=2*pi-atan(0.2/1.21), angle2=2*pi+atan(0.2/1.21), ccw=True)\nd = 1+1.21*cos(atan(.2/1.21))\nbr.append([d,0.2])\nbr.append([d,-0.2])\nbr.append(br[0])\nbre = extrusion(path=[vec(0.4,0,0),vec(1.6,0,0)], color=vec(0.1,0.1,0.15),\n texture=textures.rough, shape=br)\nd = bre.clone()\nd.rotate(angle=pi, axis=vec(1,0,0), origin=vec(1,0,0))\n\n#==========================================================================\n# Create Brush Housings\n# Define a rectangular frame, with a thickness of 0.1\nbh = shapes.rectangle(width=1.3, height=0.5, thickness=0.1)\n# Extrude the rectangular frame to obtain hollow boxes for each housing\nbhe1 = extrusion(path=[vec(1,0,1.4),vec(1,0,2.9)], shape=bh, color=vec(0.9,1,0.8),\n texture=textures.rough)\nbhe2 = extrusion(path=[vec(1,0,-1.4),vec(1,0,-2.9)], shape=bh, color=vec(0.9,1,0.8),\n texture=textures.rough)\n\n#==========================================================================\n# Place a screw on each housing to fix the power cables\n# Create a screw head profile by subtracting a cross from a circle\nscrh = [shapes.circle(radius=0.15)]\nscrh.append(shapes.cross(width=0.2, thickness=0.04))\n# Extrude a little to get the screw head\nscrhw1path = [vec(1,0.2,2.7),vec(1,0.3,2.7)]\nscrhw2path = [vec(1,0.2,-2.7),vec(1,0.3,-2.7)]\nscrhw1 = extrusion(path=scrhw1path, shape=scrh, texture=textures.metal)\nscrhw2 = extrusion(path=scrhw2path, shape=scrh, texture=textures.metal)\n\n#==========================================================================\n# Create the screw bodies\n# Use a square to create the body with teeth\nscrb = shapes.rectangle(scale=0.05)\nyi = .2\nyf = -.3\ndy = (yi-yf)/20\npts = []\nfor i in range(20):\n pts.append(vec(1, yi-i*dy, 2.7))\n# Extrude the square with twist parameter to get the teeth of the screw\n# It appears that paths.line() is broken.\n#scrbe1 = extrusion(path=paths.line(start=vec(2.7,0.2,1), end=vec(2.7,-0.3,1),\nscrbe1 = extrusion(path=pts, shape=scrb, twist=0.4, color=vec(1,1,0.9),\n texture=textures.rough)\n\npts = []\nfor i in range(20):\n pts.append(vec(1, yi-i*dy, -2.7))\nscrbe2 = extrusion(path=pts, shape=scrb, twist=0.4, color=vec(1,1,0.9),\n texture=textures.rough)\n\n#==========================================================================\n\ncrdl = [ [2.8,-0.2], [2.8,-1.6], [-2.8,-1.6], [-2.8,-0.2] ] # ccw\na = acos(0.2/1.1) # starting angle for near half-circle\nc = makearc(center=[0,0], radius=1.25, angle1=1.5*pi-a, angle2=1.5*pi+a, ccw=True)\ncrdl.extend(c)\ncrdl.append(crdl[0])\ncrdl = [crdl, shapes.circle(pos=[-2.2,-0.9], radius=0.1)]\ncrdle = extrusion(path=[vec(1.8,-0.05,0),vec(0.2,-0.05,0)], shape=crdl,\n color=0.7*color.white, emissive=True)\n\n#==========================================================================\n# Connect power cables to the brushes\n# Use simple curves to define cables\ncol = vec(1,0.5,0.3)\ncbl1i = curve(pos=[scrhw1path[0], scrhw1path[0]- vec(0,0,-2)],\n radius=0.03, color=col)\ncbl1o = curve(pos=[scrhw1path[0], scrhw1path[0]- vec(0,0,-1.5)],\n radius=0.05, color=vec(0,0,1))\ncb12ipos = [scrhw2path[0], scrhw2path[0], scrhw2path[0]+vec(0,0,-0.5), \n scrhw2path[0]+vec(0,0,-0.5)+vec(0,-2,0),\n scrhw2path[0]+vec(0,0,-0.5)+vec(0,-2,0)+vec(0,0,7)]\ncbl2i = curve(pos=cb12ipos, radius=0.03, color=col)\n\n#==========================================================================\n# Add ball-bearings at both ends of the shaft\nbra = shapes.circle(radius=0.6, thickness=0.2)\nbrb = shapes.circle(radius=1.1, thickness=0.2)\nbr1 = extrusion(path=[vec(2.5,0,0), vec(3.25,0,0)], shape=bra, color=color.gray(.7))\nbr1 = extrusion(path=[vec(2.5,0,0), vec(3.25,0,0)], shape=brb, color=color.gray(.7))\nbr2 = extrusion(path=[vec(-7,0,0), vec(-7.75,0,0)], shape=bra, color=color.gray(.7),\n shininess=1, texture=textures.metal)\nbr2 = extrusion(path=[vec(-7,0,0), vec(-7.75,0,0)], shape=brb, color=color.gray(.7),\n shininess=1, texture=textures.metal)\n\n#==========================================================================\n# Do not forget to add the balls\nbbrs1 = []\nbbrs2 = []\nfor i in range(7):\n ex1 = sphere(pos=vec(3, 0.75*cos(i*2*pi/7.0), 0.75*sin(i*2*pi/7.0)),\n radius=0.25)\n bbrs1.append(ex1)\n \n ex2 = sphere(pos=vec(-7.375, 0.75*cos(i*2*pi/7.0), 0.75*sin(i*2*pi/7.0)),\n radius=0.25)\n bbrs2.append(ex2)\nmotor.append(compound(bbrs1, texture=textures.rough))\nmotor.append(compound(bbrs2, texture=textures.rough))\n\n#==========================================================================\n# Here is a complex path definition for stator winding, which is not planar.\n# The path is made up of an arc in YZ + line in ZX + arc in ZY + line in XZ\npp = paths.arc(angle1=-pi/3.5, angle2=pi/3.5, radius=3.4)\nfor p in pp:\n p.y = -p.x\n p.x = -1\ntt = []\nfor p in pp:\n tt.append(vec(-6,p.y,p.z))\ntt.reverse()\npp.extend(tt)\npp.append(pp[0])\nextrusion(path=pp, shape=shapes.circle(radius=0.3), color=color.red)\n \n#==========================================================================\n# Make stator base:\n# We did not include all stator parts here for better visualisation\n# Use a rounded rectangle for the stator base.\n# Subtract a large circle in the middle to allow for the rotor\n# Subtract circular holes to place the stator windings\n# Subtract some more holes for fixing the stator core on the motor body\n\n#def makearc(center=[0,0], radius=1, angle1=2*pi-pi/4, angle2=2*pi+pi/4, ccw=True):\n # Specify angle1 and angle2 as positive numbers, with angle2 > angle1\np1 = makearc(center=[1.5,0], radius=1.5, angle1=3*pi/2, angle2=2*pi, ccw=True)\np2 = makearc(center=[2.7,0.22], radius=0.3, angle1=pi+pi/4, angle2=2*pi-pi/4, ccw=False)\np3 = makearc(center=[0,2.1], radius=3.1, angle1=pi+0.95*pi/4, angle2=2*pi-0.95*pi/4, ccw=False)\np4 = makearc(center=[-2.7,0.22], radius=0.3, angle1=pi+pi/4, angle2=2*pi-pi/4, ccw=False)\np5 = makearc(center=[-1.5,0], radius=1.5, angle1=pi, angle2=1.5*pi, ccw=True)\n\np1.extend(p2)\np1.extend(p3)\np1.extend(p4)\np1.extend(p5)\np1.append(p1[0])\n\nh1 = shapes.circle(pos=[2,-1.07], radius=0.15)\nh2 = shapes.circle(pos=[-2,-1.07], radius=0.15)\n\nextrusion(path=[vec(-6,-2.3,0), vec(-1,-2.3,0)], shape=[p1,h1,h2])\n\n#==========================================================================\n# Create the motor cover as a rotational extrusion along the mootor\n# Add two rounded rectangles which will cover all the rotor and stator.\n# Leave the tips of shaft outside the cover\nL = 11\nr = 2\nR = 5\nt = 0.25\nx = 3*t\ns = [ [-L/2, -r/2-t], [-L/2,-r/2], [-L/2+x,-r/2], [-L/2+x,R/2], [L/2-x,R/2], [L/2-x,-r/2], [L/2,-r/2],\n [L/2,-r/2-t], [L/2-x-t,-r/2-t], [L/2-x-t,R/2-t], [-L/2+x+t,R/2-t], \n [-L/2+x+t,-r/2-t], [-L/2+t,-r/2-t], [-L/2,-r/2-t] ]\n\np = paths.arc(radius=R/2, angle1=0, angle2=pi+pi/4)\nex = extrusion(path=p, shape=s, color=0.6*color.green, up=vec(1,0,0), texture=textures.rough)\nex.rotate(angle=pi/2, axis=vec(0,0,1))\nex.pos = vec(-2.2,0,-0.65)\n\nrun = True\ndef running(b):\n global run\n if b.text == 'Run': b.text = 'Pause'\n else: b.text = 'Run'\n run = not run\n \nbutton(text='Pause', bind=running)\n\nscene.append_to_caption(\"\"\"\\nTo rotate \"camera\", drag with right button or Ctrl-drag.\nTo zoom, drag with middle button or Alt/Option depressed, or use scroll wheel.\n On a two-button mouse, middle is left + right.\nTo pan left/right and up/down, Shift-drag.\nTouch screen: pinch/extend to zoom, swipe or two-finger rotate.\"\"\")\n\n# Connect power cables\nangl = pi/400\n# Turn on the motor\nwhile True:\n rate(100)\n if run:\n for o in motor:\n o.rotate(angle=angl, axis=vec(-1,0,0))\n \n\n ","metadata":{"trusted":false},"outputs":[{"data":{"text/plain":"","text/html":"
"},"metadata":{},"output_type":"display_data"},{"metadata":{},"data":{"text/plain":"","application/javascript":"if (typeof Jupyter !== \"undefined\") { window.__context = { glowscript_container: $(\"#glowscript\").removeAttr(\"id\")};}else{ element.textContent = ' ';}"},"output_type":"display_data"},{"output_type":"display_data","data":{"text/html":"
","text/plain":""},"metadata":{}},{"metadata":{},"output_type":"display_data","data":{"application/javascript":"if (typeof Jupyter !== \"undefined\") { window.__context = { glowscript_container: $(\"#glowscript\").removeAttr(\"id\")};}else{ element.textContent = ' ';}","text/plain":""}}],"execution_count":null},{"id":"e329e81d-2c60-4e49-ae5b-f0fa19add348","cell_type":"code","source":"","metadata":{"trusted":false},"outputs":[],"execution_count":null}]} \ No newline at end of file diff --git a/Demos_no_notebook/CORS.py b/Demos_no_notebook/CORS.py new file mode 100644 index 0000000..00770e8 --- /dev/null +++ b/Demos_no_notebook/CORS.py @@ -0,0 +1,17 @@ +from vpython import * +scene.range = 1 +scene.forward = vector(-1,-.5,-1) +box(texture="https://s3.amazonaws.com/glowscript/textures/flower_texture.jpg") + +s = 'This illustrates the use of an image from another web site as a texture.\n' +s += 'This is an example of CORS, "Cross-Origin Resource Sharing".\n' +scene.caption = s + +scene.append_to_caption(""" +To rotate "camera", drag with right button or Ctrl-drag. +To zoom, drag with middle button or Alt/Option depressed, or use scroll wheel. + On a two-button mouse, middle is left + right. +To pan left/right and up/down, Shift-drag. +Touch screen: pinch/extend to zoom, swipe or two-finger rotate.""") + +scene.pause() diff --git a/Demos_no_notebook/Conch.py b/Demos_no_notebook/Conch.py new file mode 100644 index 0000000..c7d72dc --- /dev/null +++ b/Demos_no_notebook/Conch.py @@ -0,0 +1,40 @@ +from vpython import * +# Kadir Haldenbilen, Feb. 2011 + +scene.height = scene.width = 600 +scene.background = color.gray(0.7) +scene.range = 3 +scene.ambient = 0.5*color.white + +scene.caption = """To rotate "camera", drag with right button or Ctrl-drag. +To zoom, drag with middle button or Alt/Option depressed, or use scroll wheel. + On a two-button mouse, middle is left + right. +To pan left/right and up/down, Shift-drag. +Touch screen: pinch/extend to zoom, swipe or two-finger rotate.""" + +def spiral(nloop=1, tightness=1.0, dir=1, scale=1): + spr = [] + scale = [] + clrs = [] + zd = 0.01 + for t in range(1, 1024*nloop, 16): + t *= 0.01 + x = tightness/10 * t * cos(t)*dir + y = tightness/10 * t * sin(t) + sc = sqrt(x*x+y*y) + z = t/7 + spr.append(vector(x,y,z)) + clr = vector(z*cos(t), abs(sin(t)), abs(cos(t*2))).norm() + clrs.append(clr) + scale.append(sc) + return spr, scale, clrs + +path, scale, clrs = spiral(nloop=2, tightness=0.8) +elps = shapes.circle(radius=0.69, thickness=0.01) + +ee = extrusion(shape=elps, path=path, color=clrs, scale=scale, texture=textures.rock) +ee.rotate(angle=pi/2) +scene.center = ee.pos-vec(0,.5,0) + +scene.pause() + diff --git a/Demos_no_notebook/ElectricMotor.py b/Demos_no_notebook/ElectricMotor.py new file mode 100644 index 0000000..2c3f98a --- /dev/null +++ b/Demos_no_notebook/ElectricMotor.py @@ -0,0 +1,360 @@ +from vpython import * +# Kadir Haldenbilen, February 2011 +# Converted to Web VPython by Bruce Sherwood, May 2022 + +scene.width = 1024 +scene.height = 768 +scene.center = vec(-2,0,0) +scene.range = 7 + +motor = [] # elements that rotate +cl = 2 +ns = 24 + +def makearc(center=[0,0], radius=1, angle1=2*pi-pi/4, angle2=2*pi+pi/4, ccw=True): + # Specify angle1 and angle2 as positive numbers, with angle2 > angle1 + if angle2 < angle1: + raise Exception("Both angles must be positive, with angle2 > angle1") + n = 20 + dtheta = abs(angle2-angle1)/n + ret = [] + for i in range(n+1): + if ccw: + #print(center, angle1, angle2, radius, ccw) + ret.append([center[0]+radius*cos(angle1+i*dtheta), center[1]+radius*sin(angle1+i*dtheta)]) + else: + #print(center, angle1, angle2, radius, ccw) + ret.append([center[0]+radius*cos(angle2-i*dtheta), center[1]+radius*sin(angle2-i*dtheta)]) + return ret + +def rotatepoints(points=[[1,0],[0,1]], angle=0, origin=vec(0,0,0)): + s = sphere(visible=False) + ret = [] + for p in points: + s.pos = vec(p[0],p[1],0) + s.rotate(angle=angle, axis=vec(0,0,1), origin=origin) + ret.append([s.pos.x,s.pos.y]) + return ret + +#===================================================================== +# Create contactor + +p2 = makearc(center=[0,0], radius=0.5, angle1=0, angle2=pi/20, ccw=False) +p1 = makearc(center=[0,0], radius=1.2, angle1=0, angle2=pi/15, ccw=True) +p = p1+p2+[p1[0]] +c = extrusion(path=[vec(0,0,0),vec(2,0,0)], shape=p, color=vec(1,0.5,0.3)) +cont = [c] +for i in range(1,24): + con = c.clone() + con.rotate(angle=i*2*pi/24, axis=vec(-1,0,0), origin=vec(0,0,0)) + cont.append(con) +motor.append(compound(cont)) +#========================================================================== +# Create contactor soldering tips + +p1 = makearc(center=[0,0], radius=1.4, angle1=2*pi-0.5*pi/24, angle2=2*pi+0.4*pi/24, ccw=True) +p2 = makearc(center=[0,0], radius=0.7, angle1=2*pi-0.5*pi/30, angle2=2*pi+0.4*pi/30, ccw=False) +p = p1+p2+[p1[0]] +c = extrusion(path=[vec(-0.4,0,0),vec(0,0,0)], shape=p, color=vec(1,0.5,0.3)) +s = sphere(pos=vec(-0.2,0,1.195), radius=0.1, shininess=1) +cont = [c] +balls = [] +for i in range(23): + con = c.clone() + con.rotate(angle=(i+1)*2*pi/24, axis=vec(1,0,0), origin=vec(0,0,0)) + cont.append(con) + con = s.clone() + con.rotate(angle=(i+1)*2*pi/24, axis=vec(1,0,0), origin=vec(0,0,0)) + balls.append(con) + +motor.append(compound(cont)) +motor.append(compound(balls)) +#========================================================================= +# Add shaft insulator material +# Define a circular ring of thickness=0.05 +sc = shapes.circle(radius=0.53, thickness=0.05) +# Extrude the ring to get a thin hollow cylinder insulator over the shaft +sce = extrusion(path=[vec(-7,0,0),vec(2.5,0,0)], shape=sc, color=vec(0.8,0,0), + emissive=True) # plastic + +# The Rotor Shaft, defined by a simple cylinder +shaft = cylinder(pos=vec(3.5,0,0), axis=vec(-11.25,0,0), radius=0.495, color=color.gray(.6), texture=textures.metal) + +# Add a piece of gear at one end of the shaft +# Use the gear shape to define the shape, note radius, addendum, dedendum sizes +gr = shapes.gear(n=9, radius=0.455, addendum=0.04, dedendum=0.06, fradius=0.01) +# Extrude the gear shape appending it to the shaft end +gre = extrusion(path=[vec(3.5,0,0),vec(5,0,0)], shape=gr, color=color.gray(.6), + texture=textures.metal) + +motor.append(gre) +#for o in scene.objects: o.visible = False +#========================================================================== +# Define Rotor Core +# Normally the core should have been built of many very thin sheets +# For performance reasons, a single block is built +# First define the outer circle + +r0 = 0.495 # radius of shaft +r1 = 1.3 # radius of disk +r2 = 2.7 # radius of inner portion of top of the T +r3 = 3 # radius of outer portion of top of the T +theta = pi/12 # angle between Ts +d = 0.25*theta # half angle width of upright of T +dlt = 0.05 +thk = 5.04 + +p1 = makearc(center=[0,0], radius=r1, angle1=2*pi-pi/12+d, angle2=2*pi+pi/12-d, ccw=True) +start = r1*vec(cos(-pi/12+d), sin(-pi/12+d),0) +# From middle of bottom of T base to middle of top of T upright: +middledir = vec(cos(pi/12),sin(pi/12), 0) +perp = middledir.rotate(angle=pi/2, axis=vec(0,0,1)) +p1end = vec(p1[-1][0], p1[-1][1],0) +endpt1 = p1end+(r2-r1)*middledir # top right of T upright +nextstart = start.rotate(angle=pi/6, axis=vec(0,0,1)) +endpt2 = nextstart + (r2-r1)*middledir +a = atan(endpt1.y/endpt1.x) +p2 = makearc(center=[0,0], radius=r2, angle1=0.3*a, angle2=a, ccw=False) +p1.extend(p2) +p3 = makearc(center=[0,0], radius=r3, angle1=0.3*a, angle2=1.5*a+2*d, ccw=True) +p1.extend(p3) +b = atan(endpt2.y/endpt2.x) +p4 = makearc(center=[0,0], radius=r2, angle1=b, angle2=1.5*a+2*d, ccw=False) +p1.extend(p4) + +pc = p1.copy() +for i in range(1,12): + p = rotatepoints(p1, angle=i*pi/6) + pc.extend(p) +pc.append(pc[0]) + +ex = extrusion(path=[vec(-6,0,0), vec(-6+thk,0,0)], shape=[pc, shapes.circle(radius=r0)] , color=color.gray(0.7)) +motor.append(ex) + +#========================================================================== +# Do the core wire windings +x = -3.5 +n = 20 +L = 1.3 +thk = L/50 +con = [] +for i in range(n): + r = r1+i*thk*2.5 + inner = shapes.rectangle(width=5.2, height=.35, roundness=0.4) + outer = shapes.rectangle(width=5.3+i*0.7/n, height=0.4+i*0.6/n, roundness=0.4) + p = [vec(x,r*sin(pi/12),r*cos(pi/12)), vec(x,(r+thk)*sin(pi/12),(r+thk)*cos(pi/12))] + ex = extrusion(path=p, shape=[outer,inner], color=vec(.7,.5,.15)) + con.append(ex) +ex = compound(con) +con = [ex] + +for i in range(1,12): + c = ex.clone() + c.rotate(angle=i*pi/6, axis=vec(1,0,0), origin=vec(0,0,0)) + con.append(c) + +motor.append(compound(con)) + +#========================================================================== +# Connect contactor surfaces to windings with cables +pos = vec(-1.3,1.1,0) +c0 = cylinder(pos=pos, axis=vec(-0.25,1.2,0.25)-pos, radius=0.05, color=color.blue) +con = [c0] +for i in range(1,24): + c = c0.clone() + c.rotate(angle=i*pi/6, axis=vec(1,0,0), origin=vec(c0.pos.x,0,0)) + con.append(c) +motor.append(compound(con)) + +#========================================================================== +# Create Brushes +# From a rectangular cross section, subtract rotor contactor circle, leaving us two +# brushes on each sides of the contactor, with circular profile +#br = shapes.rectangle(width=5, height=0.4) +br = makearc(center=[0,0], radius=1.21, angle1=2*pi-atan(0.2/1.21), angle2=2*pi+atan(0.2/1.21), ccw=True) +d = 1+1.21*cos(atan(.2/1.21)) +br.append([d,0.2]) +br.append([d,-0.2]) +br.append(br[0]) +bre = extrusion(path=[vec(0.4,0,0),vec(1.6,0,0)], color=vec(0.1,0.1,0.15), + texture=textures.rough, shape=br) +d = bre.clone() +d.rotate(angle=pi, axis=vec(1,0,0), origin=vec(1,0,0)) + +#========================================================================== +# Create Brush Housings +# Define a rectangular frame, with a thickness of 0.1 +bh = shapes.rectangle(width=1.3, height=0.5, thickness=0.1) +# Extrude the rectangular frame to obtain hollow boxes for each housing +bhe1 = extrusion(path=[vec(1,0,1.4),vec(1,0,2.9)], shape=bh, color=vec(0.9,1,0.8), + texture=textures.rough) +bhe2 = extrusion(path=[vec(1,0,-1.4),vec(1,0,-2.9)], shape=bh, color=vec(0.9,1,0.8), + texture=textures.rough) + +#========================================================================== +# Place a screw on each housing to fix the power cables +# Create a screw head profile by subtracting a cross from a circle +scrh = [shapes.circle(radius=0.15)] +scrh.append(shapes.cross(width=0.2, thickness=0.04)) +# Extrude a little to get the screw head +scrhw1path = [vec(1,0.2,2.7),vec(1,0.3,2.7)] +scrhw2path = [vec(1,0.2,-2.7),vec(1,0.3,-2.7)] +scrhw1 = extrusion(path=scrhw1path, shape=scrh, texture=textures.metal) +scrhw2 = extrusion(path=scrhw2path, shape=scrh, texture=textures.metal) + +#========================================================================== +# Create the screw bodies +# Use a square to create the body with teeth +scrb = shapes.rectangle(scale=0.05) +yi = .2 +yf = -.3 +dy = (yi-yf)/20 +pts = [] +for i in range(20): + pts.append(vec(1, yi-i*dy, 2.7)) +# Extrude the square with twist parameter to get the teeth of the screw +# It appears that paths.line() is broken. +#scrbe1 = extrusion(path=paths.line(start=vec(2.7,0.2,1), end=vec(2.7,-0.3,1), +scrbe1 = extrusion(path=pts, shape=scrb, twist=0.4, color=vec(1,1,0.9), + texture=textures.rough) + +pts = [] +for i in range(20): + pts.append(vec(1, yi-i*dy, -2.7)) +scrbe2 = extrusion(path=pts, shape=scrb, twist=0.4, color=vec(1,1,0.9), + texture=textures.rough) + +#========================================================================== + +crdl = [ [2.8,-0.2], [2.8,-1.6], [-2.8,-1.6], [-2.8,-0.2] ] # ccw +a = acos(0.2/1.1) # starting angle for near half-circle +c = makearc(center=[0,0], radius=1.25, angle1=1.5*pi-a, angle2=1.5*pi+a, ccw=True) +crdl.extend(c) +crdl.append(crdl[0]) +crdl = [crdl, shapes.circle(pos=[-2.2,-0.9], radius=0.1)] +crdle = extrusion(path=[vec(1.8,-0.05,0),vec(0.2,-0.05,0)], shape=crdl, + color=0.7*color.white, emissive=True) + +#========================================================================== +# Connect power cables to the brushes +# Use simple curves to define cables +col = vec(1,0.5,0.3) +cbl1i = curve(pos=[scrhw1path[0], scrhw1path[0]- vec(0,0,-2)], + radius=0.03, color=col) +cbl1o = curve(pos=[scrhw1path[0], scrhw1path[0]- vec(0,0,-1.5)], + radius=0.05, color=vec(0,0,1)) +cb12ipos = [scrhw2path[0], scrhw2path[0], scrhw2path[0]+vec(0,0,-0.5), + scrhw2path[0]+vec(0,0,-0.5)+vec(0,-2,0), + scrhw2path[0]+vec(0,0,-0.5)+vec(0,-2,0)+vec(0,0,7)] +cbl2i = curve(pos=cb12ipos, radius=0.03, color=col) + +#========================================================================== +# Add ball-bearings at both ends of the shaft +bra = shapes.circle(radius=0.6, thickness=0.2) +brb = shapes.circle(radius=1.1, thickness=0.2) +br1 = extrusion(path=[vec(2.5,0,0), vec(3.25,0,0)], shape=bra, color=color.gray(.7)) +br1 = extrusion(path=[vec(2.5,0,0), vec(3.25,0,0)], shape=brb, color=color.gray(.7)) +br2 = extrusion(path=[vec(-7,0,0), vec(-7.75,0,0)], shape=bra, color=color.gray(.7), + shininess=1, texture=textures.metal) +br2 = extrusion(path=[vec(-7,0,0), vec(-7.75,0,0)], shape=brb, color=color.gray(.7), + shininess=1, texture=textures.metal) + +#========================================================================== +# Do not forget to add the balls +bbrs1 = [] +bbrs2 = [] +for i in range(7): + ex1 = sphere(pos=vec(3, 0.75*cos(i*2*pi/7.0), 0.75*sin(i*2*pi/7.0)), + radius=0.25) + bbrs1.append(ex1) + + ex2 = sphere(pos=vec(-7.375, 0.75*cos(i*2*pi/7.0), 0.75*sin(i*2*pi/7.0)), + radius=0.25) + bbrs2.append(ex2) +motor.append(compound(bbrs1, texture=textures.rough)) +motor.append(compound(bbrs2, texture=textures.rough)) + +#========================================================================== +# Here is a complex path definition for stator winding, which is not planar. +# The path is made up of an arc in YZ + line in ZX + arc in ZY + line in XZ +pp = paths.arc(angle1=-pi/3.5, angle2=pi/3.5, radius=3.4) +for p in pp: + p.y = -p.x + p.x = -1 +tt = [] +for p in pp: + tt.append(vec(-6,p.y,p.z)) +tt.reverse() +pp.extend(tt) +pp.append(pp[0]) +extrusion(path=pp, shape=shapes.circle(radius=0.3), color=color.red) + +#========================================================================== +# Make stator base: +# We did not include all stator parts here for better visualisation +# Use a rounded rectangle for the stator base. +# Subtract a large circle in the middle to allow for the rotor +# Subtract circular holes to place the stator windings +# Subtract some more holes for fixing the stator core on the motor body + +#def makearc(center=[0,0], radius=1, angle1=2*pi-pi/4, angle2=2*pi+pi/4, ccw=True): + # Specify angle1 and angle2 as positive numbers, with angle2 > angle1 +p1 = makearc(center=[1.5,0], radius=1.5, angle1=3*pi/2, angle2=2*pi, ccw=True) +p2 = makearc(center=[2.7,0.22], radius=0.3, angle1=pi+pi/4, angle2=2*pi-pi/4, ccw=False) +p3 = makearc(center=[0,2.1], radius=3.1, angle1=pi+0.95*pi/4, angle2=2*pi-0.95*pi/4, ccw=False) +p4 = makearc(center=[-2.7,0.22], radius=0.3, angle1=pi+pi/4, angle2=2*pi-pi/4, ccw=False) +p5 = makearc(center=[-1.5,0], radius=1.5, angle1=pi, angle2=1.5*pi, ccw=True) + +p1.extend(p2) +p1.extend(p3) +p1.extend(p4) +p1.extend(p5) +p1.append(p1[0]) + +h1 = shapes.circle(pos=[2,-1.07], radius=0.15) +h2 = shapes.circle(pos=[-2,-1.07], radius=0.15) + +extrusion(path=[vec(-6,-2.3,0), vec(-1,-2.3,0)], shape=[p1,h1,h2]) + +#========================================================================== +# Create the motor cover as a rotational extrusion along the mootor +# Add two rounded rectangles which will cover all the rotor and stator. +# Leave the tips of shaft outside the cover +L = 11 +r = 2 +R = 5 +t = 0.25 +x = 3*t +s = [ [-L/2, -r/2-t], [-L/2,-r/2], [-L/2+x,-r/2], [-L/2+x,R/2], [L/2-x,R/2], [L/2-x,-r/2], [L/2,-r/2], + [L/2,-r/2-t], [L/2-x-t,-r/2-t], [L/2-x-t,R/2-t], [-L/2+x+t,R/2-t], + [-L/2+x+t,-r/2-t], [-L/2+t,-r/2-t], [-L/2,-r/2-t] ] + +p = paths.arc(radius=R/2, angle1=0, angle2=pi+pi/4) +ex = extrusion(path=p, shape=s, color=0.6*color.green, up=vec(1,0,0), texture=textures.rough) +ex.rotate(angle=pi/2, axis=vec(0,0,1)) +ex.pos = vec(-2.2,0,-0.65) + +run = True +def running(b): + global run + if b.text == 'Run': b.text = 'Pause' + else: b.text = 'Run' + run = not run + +button(text='Pause', bind=running) + +scene.append_to_caption("""\nTo rotate "camera", drag with right button or Ctrl-drag. +To zoom, drag with middle button or Alt/Option depressed, or use scroll wheel. + On a two-button mouse, middle is left + right. +To pan left/right and up/down, Shift-drag. +Touch screen: pinch/extend to zoom, swipe or two-finger rotate.""") + +# Connect power cables +angl = pi/400 +# Turn on the motor +while True: + rate(100) + if run: + for o in motor: + o.rotate(angle=angl, axis=vec(-1,0,0)) + diff --git a/setup.py b/setup.py index 2c4fcfa..cb4a0ea 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ extensions = [Extension('vpython.cyvector', ['vpython/cyvector.c'])] -install_requires = ['jupyter', 'jupyter-server-proxy', 'jupyterlab-vpython>=3.1.7', 'numpy', 'ipykernel', +install_requires = ['jupyter', 'jupyter-server-proxy', 'jupyterlab-vpython>=3.1.8', 'numpy', 'ipykernel', 'autobahn>=22.6.1, <27'] setup_args = dict(