Visualization server is now in a separate project and runnng on peteshadbolt.co.uk. Still need to update examples, tests and docs.master
| @@ -1 +0,0 @@ | |||||
| recursive-include abp/static * | |||||
| @@ -1,91 +0,0 @@ | |||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | |||||
| <svg | |||||
| xmlns:dc="http://purl.org/dc/elements/1.1/" | |||||
| xmlns:cc="http://creativecommons.org/ns#" | |||||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||||
| xmlns:svg="http://www.w3.org/2000/svg" | |||||
| xmlns="http://www.w3.org/2000/svg" | |||||
| xmlns:xlink="http://www.w3.org/1999/xlink" | |||||
| xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||||
| xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||||
| width="64" | |||||
| height="64" | |||||
| id="svg2" | |||||
| version="1.1" | |||||
| inkscape:version="0.48.4 r9939" | |||||
| sodipodi:docname="New document 1"> | |||||
| <defs | |||||
| id="defs4"> | |||||
| <linearGradient | |||||
| id="linearGradient3763"> | |||||
| <stop | |||||
| style="stop-color:#ffffff;stop-opacity:1;" | |||||
| offset="0" | |||||
| id="stop3765" /> | |||||
| <stop | |||||
| style="stop-color:#000000;stop-opacity:1;" | |||||
| offset="1" | |||||
| id="stop3767" /> | |||||
| </linearGradient> | |||||
| <radialGradient | |||||
| inkscape:collect="always" | |||||
| xlink:href="#linearGradient3763" | |||||
| id="radialGradient3771" | |||||
| cx="38.780914" | |||||
| cy="23.33404" | |||||
| fx="38.780914" | |||||
| fy="23.33404" | |||||
| r="32.661938" | |||||
| gradientUnits="userSpaceOnUse" | |||||
| gradientTransform="matrix(1.1215552,0.13870084,-0.14202472,1.1484324,1.1779947,-9.189628)" /> | |||||
| </defs> | |||||
| <sodipodi:namedview | |||||
| id="base" | |||||
| pagecolor="#ffffff" | |||||
| bordercolor="#666666" | |||||
| borderopacity="1.0" | |||||
| inkscape:pageopacity="0.0" | |||||
| inkscape:pageshadow="2" | |||||
| inkscape:zoom="3.959798" | |||||
| inkscape:cx="-12.465613" | |||||
| inkscape:cy="8.3918647" | |||||
| inkscape:document-units="px" | |||||
| inkscape:current-layer="layer1" | |||||
| showgrid="false" | |||||
| inkscape:snap-page="false" | |||||
| inkscape:window-width="1366" | |||||
| inkscape:window-height="721" | |||||
| inkscape:window-x="0" | |||||
| inkscape:window-y="0" | |||||
| inkscape:window-maximized="1" /> | |||||
| <metadata | |||||
| id="metadata7"> | |||||
| <rdf:RDF> | |||||
| <cc:Work | |||||
| rdf:about=""> | |||||
| <dc:format>image/svg+xml</dc:format> | |||||
| <dc:type | |||||
| rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||||
| <dc:title></dc:title> | |||||
| </cc:Work> | |||||
| </rdf:RDF> | |||||
| </metadata> | |||||
| <g | |||||
| inkscape:label="Layer 1" | |||||
| inkscape:groupmode="layer" | |||||
| id="layer1" | |||||
| transform="translate(0,-988.36218)"> | |||||
| <path | |||||
| sodipodi:type="arc" | |||||
| style="fill:url(#radialGradient3771);fill-opacity:1;stroke:#000000;stroke-width:1.32387710000000003;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" | |||||
| id="path2993" | |||||
| sodipodi:cx="32" | |||||
| sodipodi:cy="32" | |||||
| sodipodi:rx="32" | |||||
| sodipodi:ry="32" | |||||
| d="M 64,32 A 32,32 0 1 1 0,32 32,32 0 1 1 64,32 z" | |||||
| transform="matrix(0.94419643,0,0,0.94419643,1.7857143,990.14789)" /> | |||||
| </g> | |||||
| </svg> | |||||
| @@ -1,3 +0,0 @@ | |||||
| #!/bin/bash | |||||
| inkscape -z -e ball.png -w 64 -h 64 ball.svg | |||||
| inkscape -z -e tip.png -w 64 -h 64 tip.svg | |||||
| @@ -1,91 +0,0 @@ | |||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | |||||
| <svg | |||||
| xmlns:dc="http://purl.org/dc/elements/1.1/" | |||||
| xmlns:cc="http://creativecommons.org/ns#" | |||||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||||
| xmlns:svg="http://www.w3.org/2000/svg" | |||||
| xmlns="http://www.w3.org/2000/svg" | |||||
| xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||||
| xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||||
| width="64" | |||||
| height="64" | |||||
| id="svg2" | |||||
| version="1.1" | |||||
| inkscape:version="0.48.4 r9939" | |||||
| sodipodi:docname="tip.svg"> | |||||
| <defs | |||||
| id="defs4"> | |||||
| <linearGradient | |||||
| id="linearGradient3763"> | |||||
| <stop | |||||
| style="stop-color:#ffffff;stop-opacity:1;" | |||||
| offset="0" | |||||
| id="stop3765" /> | |||||
| <stop | |||||
| style="stop-color:#000000;stop-opacity:1;" | |||||
| offset="1" | |||||
| id="stop3767" /> | |||||
| </linearGradient> | |||||
| </defs> | |||||
| <sodipodi:namedview | |||||
| id="base" | |||||
| pagecolor="#ffffff" | |||||
| bordercolor="#666666" | |||||
| borderopacity="1.0" | |||||
| inkscape:pageopacity="0.0" | |||||
| inkscape:pageshadow="2" | |||||
| inkscape:zoom="3.959798" | |||||
| inkscape:cx="5.4453989" | |||||
| inkscape:cy="4.9448826" | |||||
| inkscape:document-units="px" | |||||
| inkscape:current-layer="layer1" | |||||
| showgrid="false" | |||||
| inkscape:snap-page="true" | |||||
| inkscape:window-width="1366" | |||||
| inkscape:window-height="721" | |||||
| inkscape:window-x="0" | |||||
| inkscape:window-y="0" | |||||
| inkscape:window-maximized="1" | |||||
| inkscape:snap-center="true" | |||||
| inkscape:object-nodes="true" /> | |||||
| <metadata | |||||
| id="metadata7"> | |||||
| <rdf:RDF> | |||||
| <cc:Work | |||||
| rdf:about=""> | |||||
| <dc:format>image/svg+xml</dc:format> | |||||
| <dc:type | |||||
| rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||||
| <dc:title></dc:title> | |||||
| </cc:Work> | |||||
| </rdf:RDF> | |||||
| </metadata> | |||||
| <g | |||||
| inkscape:label="Layer 1" | |||||
| inkscape:groupmode="layer" | |||||
| id="layer1" | |||||
| transform="translate(0,-988.36218)"> | |||||
| <path | |||||
| sodipodi:type="arc" | |||||
| style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.32387710000000003;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;opacity:0.29302326" | |||||
| id="path2993" | |||||
| sodipodi:cx="32" | |||||
| sodipodi:cy="32" | |||||
| sodipodi:rx="32" | |||||
| sodipodi:ry="32" | |||||
| d="M 64,32 A 32,32 0 1 1 0,32 32,32 0 1 1 64,32 z" | |||||
| transform="matrix(0.94419643,0,0,0.94419643,1.7857143,990.14789)" /> | |||||
| <path | |||||
| style="color:#000000;fill:none;stroke:#000000;stroke-width:9.65;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||||
| d="m 32,996.21932 0,48.28568" | |||||
| id="path3811" | |||||
| inkscape:connector-curvature="0" /> | |||||
| <path | |||||
| style="color:#000000;fill:none;stroke:#000000;stroke-width:9.65;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||||
| d="m 7.8571427,1020.3622 48.2857143,0" | |||||
| id="path3813" | |||||
| inkscape:connector-curvature="0" /> | |||||
| </g> | |||||
| </svg> | |||||
| @@ -1,47 +0,0 @@ | |||||
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <title>abp</title> | |||||
| <meta charset="utf-8"> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=1" /> | |||||
| <link rel="stylesheet" href="main.css"> | |||||
| <script src="scripts/three.js"></script> | |||||
| <script src="scripts/orbitcontrols.js"></script> | |||||
| <script src="scripts/anders_briegel.js"></script> | |||||
| <script src="scripts/mouse.js"></script> | |||||
| <script src="scripts/materials.js"></script> | |||||
| <script src="scripts/graph.js"></script> | |||||
| <script src="scripts/gui.js"></script> | |||||
| <script src="scripts/editor.js"></script> | |||||
| <script src="scripts/websocket.js"></script> | |||||
| <script src="scripts/main.js"></script> | |||||
| </head> | |||||
| <body> | |||||
| <img id=ball src="img/ball.png" style=display:none;> | |||||
| <img id=tip src="img/tip.png" style=display:none;> | |||||
| <div id=node_info class=hidden> nothing </div> | |||||
| <div id=server_info class=hidden> </div> | |||||
| <div id=version>Version 0.4.27</div> | |||||
| <div id=node_data class=hidden> | |||||
| <div id=node_name></div> | |||||
| <ul> | |||||
| <li id=node_vop></li> | |||||
| <li>Measure in | |||||
| <a href="#" onclick="editor.measureX()">X</a> / | |||||
| <a href="#" onclick="editor.measureY()">Y</a> / | |||||
| <a href="#" onclick="editor.measureZ()">Z</a></li> | |||||
| <li>Act | |||||
| <a href="#" onclick="editor.hadamard()">Hadamard</a> / | |||||
| <a href="#" onclick="editor.phase()">Phase</a></li> | |||||
| <li><a href="#" onclick="editor.localComplementation()">Invert neighbourhood</a></li> | |||||
| <li><a href="#" onclick="editor.deleteNode()">Delete</a></li> | |||||
| </ul> | |||||
| </div> | |||||
| </body> | |||||
| </html> | |||||
| @@ -1,105 +0,0 @@ | |||||
| html, body { margin: 0; padding: 0; overflow: hidden; font-size: 10pt; font-family: monospace; } | |||||
| #node_info { | |||||
| background: rgba(0, 0, 0, .8); | |||||
| color:white; | |||||
| padding: 5px; | |||||
| margin:0px; | |||||
| position: absolute; | |||||
| top:5px; | |||||
| left:5px; | |||||
| font-family: monospace; | |||||
| text-align: center; | |||||
| font-size:9pt; | |||||
| /*height:15px;*/ | |||||
| border-radius:3px; | |||||
| pointer-events: none; | |||||
| } | |||||
| #server_info { | |||||
| background-color: black; | |||||
| color:white; | |||||
| padding: 10px; | |||||
| font-family: monospace; | |||||
| position: absolute; | |||||
| top: 10px; | |||||
| right: 10px; | |||||
| font-size: 9pt; | |||||
| } | |||||
| #node_name { | |||||
| font-size: 12pt; | |||||
| } | |||||
| #node_data { | |||||
| background-color: black; | |||||
| color:white; | |||||
| padding: 10px; | |||||
| font-family: monospace; | |||||
| position: absolute; | |||||
| top: 10px; | |||||
| left: 10px; | |||||
| font-size: 9pt; | |||||
| } | |||||
| #options { | |||||
| background-color: rgba(256, 256, 256, .5); | |||||
| color: black; | |||||
| padding: 10px; | |||||
| font-family: monospace; | |||||
| position: absolute; | |||||
| text-align: right; | |||||
| bottom: 10px; | |||||
| right: 10px; | |||||
| font-size: 9pt; | |||||
| } | |||||
| #version { | |||||
| color:black; | |||||
| padding: 10px; | |||||
| font-family: monospace; | |||||
| position: absolute; | |||||
| bottom: 10px; | |||||
| left: 10px; | |||||
| font-size: 9pt; | |||||
| } | |||||
| ul { | |||||
| list-style-type: none; | |||||
| padding: 0px; | |||||
| margin: 0px; | |||||
| } | |||||
| li{ | |||||
| padding:3px; | |||||
| padding-left: 0em; | |||||
| } | |||||
| .visible { | |||||
| visibility: visible; | |||||
| opacity: 1; | |||||
| transform: scale(1); | |||||
| transition: opacity .08s linear, transform .08s linear; | |||||
| } | |||||
| .hidden { | |||||
| visibility: hidden; | |||||
| opacity: 0; | |||||
| transform: scale(.5); | |||||
| transition: visibility .08s, opacity .08s linear, transform .08s linear; | |||||
| } | |||||
| a { | |||||
| color: yellow; | |||||
| } | |||||
| h3 { | |||||
| padding-top: 0px; | |||||
| padding-bottom: 0px; | |||||
| margin-top: 2px; | |||||
| margin-bottom: 2px; | |||||
| } | |||||
| @@ -1 +0,0 @@ | |||||
| qcengine | |||||
| @@ -1,73 +0,0 @@ | |||||
| var abj = {}; | |||||
| abj.node = {}; | |||||
| abj.adj = {}; | |||||
| abj.add_node = function(node, meta) { | |||||
| if (meta === undefined){meta = {};} | |||||
| abj.adj[node] = {}; | |||||
| abj.node[node] = {}; | |||||
| abj.node[node].vop = tables.clifford.hadamard; | |||||
| Object.assign(abj.node[node], meta); | |||||
| }; | |||||
| abj.add_nodes = function(nodes) { | |||||
| nodes.forEach(add_node); | |||||
| }; | |||||
| abj.del_node = function(node) { | |||||
| for (var i in abj.adj[node]) { | |||||
| abj.del_edge(node, i); | |||||
| } | |||||
| delete abj.node[node]; | |||||
| }; | |||||
| abj.add_edge = function(a, b) { | |||||
| abj.adj[a][b] = {}; | |||||
| abj.adj[b][a] = {}; | |||||
| }; | |||||
| abj.add_edges = function(edges) { | |||||
| edges.forEach(function(e) { | |||||
| add_edge(e[0], e[1]); | |||||
| }); | |||||
| }; | |||||
| abj.del_edge = function(a, b) { | |||||
| delete abj.adj[a][b]; | |||||
| delete abj.adj[b][a]; | |||||
| }; | |||||
| abj.has_edge = function(a, b) { | |||||
| return Object.prototype.hasOwnProperty.call(abj.adj[a], b); | |||||
| }; | |||||
| abj.is_sole_member = function(group, node) { | |||||
| // TODO: this is slow as heck | |||||
| var keys = Object.keys(group); | |||||
| return keys.length == 1 && keys[0] == node; | |||||
| }; | |||||
| abj.update = function(newState) { | |||||
| abj.node = newState.node; | |||||
| abj.adj = newState.adj; | |||||
| }; | |||||
| abj.order = function(){ | |||||
| return Object.keys(abj.node).length; | |||||
| }; | |||||
| abj.edgelist = function() { | |||||
| var seen = {}; | |||||
| var output = []; | |||||
| for (var i in abj.adj) { | |||||
| for (var j in abj.adj[i]) { | |||||
| if (!Object.prototype.hasOwnProperty.call(seen, j)) { | |||||
| output.push([i, j]); | |||||
| } | |||||
| } | |||||
| seen[i] = true; | |||||
| } | |||||
| return output; | |||||
| }; | |||||
| @@ -1,190 +0,0 @@ | |||||
| var editor = {}; | |||||
| var pi2 = Math.PI / 2; | |||||
| editor.selection = undefined; | |||||
| editor.mouseOver = undefined; | |||||
| editor.orientations = [ | |||||
| new THREE.Euler(pi2, 0, 0), | |||||
| new THREE.Euler(0, 0, 0), | |||||
| new THREE.Euler(pi2, 0, pi2), | |||||
| ]; | |||||
| editor.onFreeMove = function() { | |||||
| var found = editor.findNodeOnRay(mouse.ray); | |||||
| if (editor.mouseOver !== found) { | |||||
| editor.mouseOver = found; | |||||
| if (found) { | |||||
| var n = abj.node[found]; | |||||
| var s = "Node " + found + "<br/> "; | |||||
| for (var i in n) { | |||||
| if (i!="position"){ | |||||
| s += i + ":" + n[i] + " "; | |||||
| } | |||||
| } | |||||
| s += ""; | |||||
| gui.nodeMessage(s); | |||||
| } else { | |||||
| gui.hideNodeMessage(); | |||||
| } | |||||
| } | |||||
| }; | |||||
| editor.focus = function(node) { | |||||
| gui.hideNodeMessage(); | |||||
| editor.selection = node; | |||||
| //gui.serverMessage("Selected node " + node + "."); | |||||
| }; | |||||
| editor.addQubitAtPoint = function(point) { | |||||
| if (point === null) { | |||||
| return; | |||||
| } | |||||
| point.round(); | |||||
| var new_node = Math.floor(point.x) + "," + Math.floor(point.y) + "," + Math.floor(point.z); | |||||
| if (Object.prototype.hasOwnProperty.call(abj.node, new_node)) { | |||||
| gui.serverMessage("Node " + new_node +" already exists."); | |||||
| return; | |||||
| } | |||||
| websocket.edit({action:"create", name:new_node, position: point}); | |||||
| editor.focus(new_node); | |||||
| gui.serverMessage("Created node " + new_node +"."); | |||||
| }; | |||||
| editor.onClick = function() { | |||||
| var found = editor.findNodeOnRay(mouse.ray); | |||||
| if (found) { | |||||
| editor.focus(found); | |||||
| var node=found; | |||||
| //editor.grid.position.copy(abj.node[node].position); | |||||
| gui.controls.target.copy(abj.node[node].position); | |||||
| node_name.innerHTML = "Node " + node; | |||||
| node_data.className = "visible"; | |||||
| node_vop.innerHTML = "VOP: " + abj.node[node].vop; | |||||
| } else { | |||||
| var intersection = mouse.ray.intersectPlane(editor.plane); | |||||
| if (intersection !== null) { | |||||
| editor.addQubitAtPoint(intersection); | |||||
| } | |||||
| } | |||||
| }; | |||||
| editor.onShiftClick = function() { | |||||
| var found = editor.findNodeOnRay(mouse.ray); | |||||
| if (found === undefined){ return; } | |||||
| if (editor.selection === undefined){ return; } | |||||
| if (found === editor.selection){ return; } | |||||
| //abj.act_cz(found, editor.selection); | |||||
| websocket.edit({action:"cz", start:found, end:editor.selection}); | |||||
| gui.serverMessage("Acted CZ between " + found + " & " + editor.selection + "."); | |||||
| editor.focus(found); | |||||
| }; | |||||
| editor.onCtrlClick = function() { | |||||
| var found = editor.findNodeOnRay(mouse.ray); | |||||
| if (found === undefined){ return; } | |||||
| if (editor.selection === undefined){ return; } | |||||
| editor.focus(found); | |||||
| websocket.edit({action:"hadamard", node:found}); | |||||
| gui.serverMessage("Acted H on node " + found + "."); | |||||
| }; | |||||
| editor.prepare = function() { | |||||
| mouse.onFreeMove = editor.onFreeMove; | |||||
| mouse.onClick = editor.onClick; | |||||
| mouse.onShiftClick = editor.onShiftClick; | |||||
| mouse.onCtrlClick = editor.onCtrlClick; | |||||
| document.addEventListener("keydown", editor.onKey, false); | |||||
| //editor.makeGrid(); | |||||
| }; | |||||
| editor.onKey = function(evt) { | |||||
| if (evt.keyCode === 32) { | |||||
| editor.setOrientation((editor.orientation + 1) % 3); | |||||
| } | |||||
| if (evt.keyCode === 46 || evt.keyCode === 68) { | |||||
| editor.deleteNode(); | |||||
| } | |||||
| }; | |||||
| editor.setOrientation = function(orientation) { | |||||
| editor.orientation = orientation; | |||||
| var rotation = editor.orientations[orientation]; | |||||
| var normal = new THREE.Vector3(0, 1, 0); | |||||
| normal.applyEuler(rotation); | |||||
| editor.grid.rotation.copy(rotation); | |||||
| editor.plane = new THREE.Plane(); | |||||
| editor.plane.setFromNormalAndCoplanarPoint(normal, editor.grid.position); | |||||
| gui.render(); | |||||
| }; | |||||
| editor.makeGrid = function() { | |||||
| editor.grid = new THREE.GridHelper(10, 1); | |||||
| editor.grid.setColors(0xbbbbbb, 0xeeeeee); | |||||
| editor.grid.renderOrder = 1000; | |||||
| editor.setOrientation(0); | |||||
| gui.scene.add(editor.grid); | |||||
| gui.scene.children[0].renderOrder = -3000; | |||||
| }; | |||||
| editor.update = function() {}; | |||||
| // Gets a reference to the node nearest to the mouse cursor | |||||
| editor.findNodeOnRay = function(ray) { | |||||
| for (var n in abj.node) { | |||||
| if (ray.distanceSqToPoint(abj.node[n].position) < 0.012) { | |||||
| return n; | |||||
| } | |||||
| } | |||||
| return undefined; | |||||
| }; | |||||
| editor.deleteNode = function() { | |||||
| if (editor.selection === undefined){ return; } | |||||
| websocket.edit({action:"delete", node:editor.selection}); | |||||
| gui.serverMessage("Deleted node " + editor.selection + "."); | |||||
| editor.selection = undefined; | |||||
| node_data.className = "hidden"; | |||||
| }; | |||||
| //TODO: loadsa space for DRY here | |||||
| editor.hadamard = function() { | |||||
| if (editor.selection === undefined){ return; } | |||||
| websocket.edit({action:"hadamard", node:editor.selection}); | |||||
| gui.serverMessage("Acted Hadamard on node " + editor.selection + "."); | |||||
| }; | |||||
| editor.phase = function() { | |||||
| if (editor.selection === undefined){ return; } | |||||
| websocket.edit({action:"phase", node:editor.selection}); | |||||
| gui.serverMessage("Acted phase on node " + editor.selection + "."); | |||||
| }; | |||||
| editor.measureX = function() { | |||||
| if (editor.selection === undefined){ return; } | |||||
| websocket.edit({action:"measure", node:editor.selection, basis:"x"}); | |||||
| gui.serverMessage("Measured node " + editor.selection + " in X."); | |||||
| }; | |||||
| editor.measureY = function() { | |||||
| if (editor.selection === undefined){ return; } | |||||
| websocket.edit({action:"measure", node:editor.selection, basis:"y"}); | |||||
| gui.serverMessage("Measured node " + editor.selection + " in Y."); | |||||
| }; | |||||
| editor.measureZ = function() { | |||||
| if (editor.selection === undefined){ return; } | |||||
| websocket.edit({action:"measure", node:editor.selection, basis:"z"}); | |||||
| gui.serverMessage("Measured node " + editor.selection + " in z."); | |||||
| }; | |||||
| editor.localComplementation = function() { | |||||
| if (editor.selection === undefined){ return; } | |||||
| websocket.edit({action:"localcomplementation", node:editor.selection}); | |||||
| abj.local_complementation(editor.selection); | |||||
| gui.serverMessage("Inverted neighbourhood of " + editor.selection + "."); | |||||
| }; | |||||
| @@ -1,76 +0,0 @@ | |||||
| var graph = {}; | |||||
| graph.colors = ["red", "green"]; | |||||
| graph.prepare = function() { | |||||
| materials.prepare(); | |||||
| websocket.connect(graph.update); | |||||
| }; | |||||
| graph.center = function() { | |||||
| var middle = new THREE.Vector3(0, 0, 0); | |||||
| for (var i in abj.node) { | |||||
| middle = middle.add(abj.node[i].position); | |||||
| } | |||||
| middle = middle.multiplyScalar(1.0/abj.order()); | |||||
| return middle; | |||||
| }; | |||||
| graph.update = function(newState) { | |||||
| if (newState){abj.update(newState);} | |||||
| var gs = gui.scene.getObjectByName("graphstate"); | |||||
| if (gs){ gui.scene.remove(gs); } | |||||
| var geometry = new THREE.Geometry(); | |||||
| geometry.colors = []; | |||||
| for (var i in abj.node) { | |||||
| var color = graph.colors[abj.node[i].vop % graph.colors.length]; | |||||
| if (abj.node[i].color !== undefined){ | |||||
| color = abj.node[i].color; | |||||
| } | |||||
| geometry.vertices.push(abj.node[i].position); | |||||
| geometry.colors.push(new THREE.Color(color)); | |||||
| } | |||||
| graph.center(); | |||||
| gui.controls.target.copy(graph.center()); | |||||
| var edges = new THREE.Object3D(); | |||||
| var my_edges = abj.edgelist(); | |||||
| for (i = 0; i < my_edges.length; ++i) { | |||||
| var edge = my_edges[i]; | |||||
| var start = abj.node[edge[0]].position; | |||||
| var startpos = new THREE.Vector3(start.x, start.y, start.z); | |||||
| var end = abj.node[edge[1]].position; | |||||
| var endpos = new THREE.Vector3(end.x, end.y, end.z); | |||||
| var newEdge = materials.makeCurve(startpos, endpos); | |||||
| edges.add(newEdge); | |||||
| } | |||||
| if (editor.selection) { | |||||
| console.log(editor.selection); | |||||
| var node = editor.selection; | |||||
| if (Object.prototype.hasOwnProperty.call(abj.node, node)) { | |||||
| editor.grid.position.copy(abj.node[node].position); | |||||
| gui.controls.target.copy(abj.node[node].position); | |||||
| node_name.innerHTML = "Node " + node; | |||||
| node_data.className = "visible"; | |||||
| node_vop.innerHTML = "VOP: " + abj.node[node].vop; | |||||
| } else { | |||||
| editor.selection = undefined; | |||||
| node_data.className = "hidden"; | |||||
| } | |||||
| } else { | |||||
| node_data.className = "hidden"; | |||||
| } | |||||
| var particles = new THREE.Points(geometry, materials.qubit); | |||||
| var object = new THREE.Object3D(); | |||||
| object.name = "graphstate"; | |||||
| object.add(particles); | |||||
| object.add(edges); | |||||
| gui.scene.add(object); | |||||
| gui.render(); | |||||
| }; | |||||
| @@ -1,80 +0,0 @@ | |||||
| var gui = {}; | |||||
| gui.prepare = function() { | |||||
| gui.renderer = new THREE.WebGLRenderer({ | |||||
| "antialias": true | |||||
| }); | |||||
| gui.renderer.setSize(window.innerWidth, window.innerHeight); | |||||
| gui.renderer.setClearColor(0xffffff, 1); | |||||
| document.querySelector("body").appendChild(gui.renderer.domElement); | |||||
| window.addEventListener("resize", gui.onWindowResize, false); | |||||
| gui.makeScene(); | |||||
| gui.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.3, 1000); | |||||
| gui.controls = new THREE.OrbitControls(gui.camera); | |||||
| gui.controls.addEventListener("change", gui.render); | |||||
| gui.controls.center.set(0, 0, 0); | |||||
| gui.controls.target.set(0, 0, 0); | |||||
| gui.controls.rotateSpeed = 0.2; | |||||
| gui.controls.userPanSpeed = 0.1; | |||||
| gui.camera.position.set(0, 0, 10); | |||||
| gui.controls.autoRotate = true; | |||||
| gui.controls.autoRotateSpeed = 0.1; | |||||
| }; | |||||
| // Someone resized the window | |||||
| gui.onWindowResize = function(evt) { | |||||
| gui.camera.aspect = window.innerWidth / window.innerHeight; | |||||
| gui.camera.updateProjectionMatrix(); | |||||
| gui.renderer.setSize(window.innerWidth, window.innerHeight); | |||||
| gui.render(); | |||||
| }; | |||||
| // Render the current frame to the screen | |||||
| gui.render = function() { | |||||
| requestAnimationFrame(function() { | |||||
| gui.renderer.render(gui.scene, gui.camera); | |||||
| }); | |||||
| }; | |||||
| // Make the extra bits of gui | |||||
| gui.makeScene = function() { | |||||
| gui.scene = new THREE.Scene(); | |||||
| }; | |||||
| // Put an HTML message to the screen | |||||
| // TODO: write a generic messaging class? | |||||
| gui.serverMessage = function(msgtext, persist) { | |||||
| if (persist === undefined) {persist = false;} | |||||
| server_info.innerHTML = msgtext; | |||||
| server_info.className = "visible"; | |||||
| clearInterval(gui.ki); | |||||
| if (!persist){ | |||||
| gui.ki = setInterval(function(){server_info.className="hidden";}, 3000); | |||||
| } | |||||
| }; | |||||
| gui.nodeMessage = function(msgtext) { | |||||
| node_info.innerHTML = msgtext; | |||||
| node_info.className = "visible"; | |||||
| }; | |||||
| gui.hideNodeMessage = function(){ | |||||
| node_info.className = "hidden"; | |||||
| }; | |||||
| // Set the position of the info popup | |||||
| gui.setInfoPosition = function(position){ | |||||
| w = node_info.offsetWidth; | |||||
| h = node_info.offsetHeight; | |||||
| node_info.style.left = position.x - w/2 + "px"; | |||||
| node_info.style.top = position.y - h -10 + "px"; | |||||
| }; | |||||
| // The main loop | |||||
| gui.loop = function() { | |||||
| gui.controls.update(); | |||||
| editor.update(); | |||||
| requestAnimationFrame(gui.loop); | |||||
| }; | |||||
| @@ -1,58 +0,0 @@ | |||||
| var mouse = {}; | |||||
| var interaction = {}; | |||||
| interaction.raycaster = new THREE.Raycaster(); | |||||
| interaction.xyplane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); | |||||
| // Gets a reference to the node nearest to the mouse cursor | |||||
| interaction.nearestNode = function() { | |||||
| this.raycaster.setFromCamera(mouse, camera); | |||||
| for (var i = 0; i < nodeGeometry.vertices.length; ++i) { | |||||
| var v = nodeGeometry.vertices[i]; | |||||
| if (this.raycaster.ray.distanceSqToPoint(v) < 0.01) { | |||||
| return i; | |||||
| } | |||||
| } | |||||
| return undefined; | |||||
| }; | |||||
| // Find out: what is the mouse pointing at? | |||||
| interaction.checkIntersections = function() { | |||||
| var new_selection = nearestNode(); | |||||
| if (new_selection != this.selection) { | |||||
| this.selection = new_selection; | |||||
| info.className = this.selection ? "visible" : "hidden"; | |||||
| info.innerHTML = this.selection ? nodeGeometry.labels[new_selection] : info.innerHTML; | |||||
| render(); | |||||
| } | |||||
| }; | |||||
| // Update the mouse position tracker | |||||
| interaction.onMouseMove = function(event) { | |||||
| mouse.wasClick = false; | |||||
| mouse.absx = event.clientX; | |||||
| mouse.absy = event.clientY; | |||||
| mouse.x = (event.clientX / window.innerWidth) * 2 - 1; | |||||
| mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; | |||||
| //w = 200; //h = 15; //info.style.top = mouse.absy - h - 40 + "px"; //info.style.left = mouse.absx - w / 2 + "px"; //checkIntersections(); | |||||
| }; | |||||
| // Try to add a qubit at the current mouse position | |||||
| interaction.addQubitAtMouse = function(event) { | |||||
| this.raycaster.setFromCamera(mouse, camera); | |||||
| var intersection = this.raycaster.ray.intersectPlane(this.plane); | |||||
| intersection.x = Math.round(intersection.x); | |||||
| intersection.y = Math.round(intersection.y); | |||||
| abj.add_node(Object.keys(vops).length, { | |||||
| "position": intersection | |||||
| }); | |||||
| updateScene(); | |||||
| } | |||||
| interaction.bind = function() { | |||||
| var el = renderer.domElement; | |||||
| el.addEventListener("mousedown", this.onMouseDown); | |||||
| el.addEventListener("mouseup", this.onMouseDown); | |||||
| el.addEventListener("mousemove", this.onMouseMove); | |||||
| }; | |||||
| @@ -1,10 +0,0 @@ | |||||
| console.log("abp v0.4.27"); | |||||
| window.onload = function() { | |||||
| graph.prepare(); | |||||
| materials.prepare(); | |||||
| gui.prepare(); | |||||
| mouse.prepare(); | |||||
| editor.prepare(); | |||||
| gui.loop(); | |||||
| }; | |||||
| @@ -1,38 +0,0 @@ | |||||
| var materials = {}; | |||||
| var curveProperties = { | |||||
| splineDensity: 10, | |||||
| curvature: 20 | |||||
| }; | |||||
| // Is called on boot | |||||
| materials.prepare = function() { | |||||
| var ballSprite = new THREE.Texture(document.getElementById("ball")); | |||||
| ballSprite.needsUpdate = true; | |||||
| materials.edge = new THREE.LineBasicMaterial({ | |||||
| color: "gray", | |||||
| transparent: false, | |||||
| linewidth: 5 | |||||
| }); | |||||
| materials.edge.depthTest = false; | |||||
| materials.qubit = new THREE.PointsMaterial({ | |||||
| size: 0.6, | |||||
| map: ballSprite, | |||||
| alphaTest: 0.5, | |||||
| transparent: true, | |||||
| vertexColors: THREE.VertexColors | |||||
| }); | |||||
| }; | |||||
| materials.makeCurve = function(a, b) { | |||||
| var length = new THREE.Vector3().subVectors(a, b).length(); | |||||
| var bend = new THREE.Vector3(length / curveProperties.curvature, length / curveProperties.curvature, 0); | |||||
| var mid = new THREE.Vector3().add(a).add(b).multiplyScalar(0.5).add(bend); | |||||
| var spline = new THREE.CatmullRomCurve3([a, mid, b]); | |||||
| var geometry = new THREE.Geometry(); | |||||
| var splinePoints = spline.getPoints(curveProperties.splineDensity); | |||||
| Array.prototype.push.apply(geometry.vertices, splinePoints); | |||||
| return new THREE.Line(geometry, materials.edge); | |||||
| }; | |||||
| @@ -1,73 +0,0 @@ | |||||
| var mouse = {}; | |||||
| mouse.wasClick = true; | |||||
| mouse.pressed = false; | |||||
| mouse.leniency = 4; | |||||
| mouse.raycaster = new THREE.Raycaster(); | |||||
| mouse.onFreeMove = function() { | |||||
| console.log("Free move"); | |||||
| }; | |||||
| mouse.onDrag = function() { | |||||
| //console.log("Drag"); | |||||
| }; | |||||
| mouse.onClick = function() { | |||||
| console.log("Click"); | |||||
| }; | |||||
| mouse.onCtrlClick = function() { | |||||
| console.log("Ctrl-click"); | |||||
| }; | |||||
| mouse.onShiftClick = function() { | |||||
| console.log("Shift-click"); | |||||
| }; | |||||
| mouse.prepare = function() { | |||||
| var el = gui.renderer.domElement; | |||||
| el.addEventListener("mousedown", mouse.onDown); | |||||
| el.addEventListener("mouseup", mouse.onUp); | |||||
| el.addEventListener("mousemove", mouse.onMove); | |||||
| }; | |||||
| mouse.onDown = function(event) { | |||||
| mouse.wasClick = true; | |||||
| mouse.pressed = true; | |||||
| mouse.startX = event.clientX; | |||||
| mouse.startY = event.clientY; | |||||
| }; | |||||
| mouse.onUp = function(event) { | |||||
| mouse.pressed = false; | |||||
| if (!mouse.wasClick) { | |||||
| return; | |||||
| } | |||||
| if (event.ctrlKey) { | |||||
| mouse.onCtrlClick(); | |||||
| } else if (event.shiftKey) { | |||||
| mouse.onShiftClick(); | |||||
| } else { | |||||
| mouse.onClick(); | |||||
| } | |||||
| }; | |||||
| mouse.onMove = function(event) { | |||||
| // TODO: wasclick sux | |||||
| if (Math.abs(event.clientX - mouse.startX)>mouse.leniency || Math.abs(event.clientY - mouse.startY)>mouse.leniency){ | |||||
| mouse.wasClick = false; | |||||
| } | |||||
| mouse.position_absolute = { | |||||
| x: event.clientX, | |||||
| y: event.clientY | |||||
| }; | |||||
| mouse.position_relative = { | |||||
| x: (event.clientX / window.innerWidth) * 2 - 1, | |||||
| y: -(event.clientY / window.innerHeight) * 2 + 1 | |||||
| }; | |||||
| gui.setInfoPosition(mouse.position_absolute); | |||||
| mouse.raycaster.setFromCamera(mouse.position_relative, gui.camera); | |||||
| mouse.ray = mouse.raycaster.ray; | |||||
| if (mouse.pressed) { | |||||
| mouse.onDrag(); | |||||
| } else { | |||||
| mouse.onFreeMove(); | |||||
| } | |||||
| }; | |||||
| @@ -1,412 +0,0 @@ | |||||
| // three.js - http://github.com/mrdoob/three.js | |||||
| /** | |||||
| * @author qiao / https://github.com/qiao | |||||
| * @author mrdoob / http://mrdoob.com | |||||
| * @author alteredq / http://alteredqualia.com/ | |||||
| * @author WestLangley / http://github.com/WestLangley | |||||
| */ | |||||
| THREE.OrbitControls = function ( object, domElement ) { | |||||
| this.object = object; | |||||
| this.domElement = ( domElement !== undefined ) ? domElement : document; | |||||
| // API | |||||
| this.enabled = true; | |||||
| this.center = new THREE.Vector3(); | |||||
| this.target = new THREE.Vector3(); | |||||
| this.userZoom = true; | |||||
| this.userZoomSpeed = 1.0; | |||||
| this.userRotate = true; | |||||
| this.userRotateSpeed = 1.0; | |||||
| this.userPan = true; | |||||
| this.userPanSpeed = 0.1; | |||||
| this.autoRotate = false; | |||||
| this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 | |||||
| this.minPolarAngle = 0; // radians | |||||
| this.maxPolarAngle = Math.PI; // radians | |||||
| this.minDistance = 0; | |||||
| this.maxDistance = Infinity; | |||||
| // 65 /*A*/, 83 /*S*/, 68 /*D*/ | |||||
| this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40, ROTATE: 65, ZOOM: 83, PAN: 68 }; | |||||
| // internals | |||||
| var scope = this; | |||||
| var EPS = 0.000001; | |||||
| var PIXELS_PER_ROUND = 1800; | |||||
| var rotateStart = new THREE.Vector2(); | |||||
| var rotateEnd = new THREE.Vector2(); | |||||
| var rotateDelta = new THREE.Vector2(); | |||||
| var zoomStart = new THREE.Vector2(); | |||||
| var zoomEnd = new THREE.Vector2(); | |||||
| var zoomDelta = new THREE.Vector2(); | |||||
| var phiDelta = 0; | |||||
| var thetaDelta = 0; | |||||
| var scale = 1; | |||||
| var lastPosition = new THREE.Vector3(); | |||||
| var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2 }; | |||||
| var state = STATE.NONE; | |||||
| // events | |||||
| var changeEvent = { type: 'change' }; | |||||
| this.rotateLeft = function ( angle ) { | |||||
| if ( angle === undefined ) { | |||||
| angle = getAutoRotationAngle(); | |||||
| } | |||||
| thetaDelta -= angle; | |||||
| }; | |||||
| this.rotateRight = function ( angle ) { | |||||
| if ( angle === undefined ) { | |||||
| angle = getAutoRotationAngle(); | |||||
| } | |||||
| thetaDelta += angle; | |||||
| }; | |||||
| this.rotateUp = function ( angle ) { | |||||
| if ( angle === undefined ) { | |||||
| angle = getAutoRotationAngle(); | |||||
| } | |||||
| phiDelta -= angle; | |||||
| }; | |||||
| this.rotateDown = function ( angle ) { | |||||
| if ( angle === undefined ) { | |||||
| angle = getAutoRotationAngle(); | |||||
| } | |||||
| phiDelta += angle; | |||||
| }; | |||||
| this.zoomIn = function ( zoomScale ) { | |||||
| if ( zoomScale === undefined ) { | |||||
| zoomScale = getZoomScale(); | |||||
| } | |||||
| scale /= zoomScale; | |||||
| }; | |||||
| this.zoomOut = function ( zoomScale ) { | |||||
| if ( zoomScale === undefined ) { | |||||
| zoomScale = getZoomScale(); | |||||
| } | |||||
| scale *= zoomScale; | |||||
| }; | |||||
| this.pan = function ( distance ) { | |||||
| distance.transformDirection( this.object.matrix ); | |||||
| distance.multiplyScalar( scope.userPanSpeed ); | |||||
| this.object.position.add( distance ); | |||||
| this.center.add( distance ); | |||||
| this.target.add( distance ); | |||||
| }; | |||||
| this.update = function () { | |||||
| var position = this.object.position; | |||||
| var offset = position.clone().sub( this.center ); | |||||
| var diff = this.center.clone().sub( this.target ).multiplyScalar(0.2); | |||||
| this.center.sub(diff); | |||||
| // angle from z-axis around y-axis | |||||
| var theta = Math.atan2( offset.x, offset.z ); | |||||
| // angle from y-axis | |||||
| var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y ); | |||||
| if ( this.autoRotate ) { | |||||
| this.rotateLeft( getAutoRotationAngle() ); | |||||
| } | |||||
| theta += thetaDelta; | |||||
| phi += phiDelta; | |||||
| // restrict phi to be between desired limits | |||||
| phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) ); | |||||
| // restrict phi to be betwee EPS and PI-EPS | |||||
| phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) ); | |||||
| var radius = offset.length() * scale; | |||||
| // restrict radius to be between desired limits | |||||
| radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) ); | |||||
| offset.x = radius * Math.sin( phi ) * Math.sin( theta ); | |||||
| offset.y = radius * Math.cos( phi ); | |||||
| offset.z = radius * Math.sin( phi ) * Math.cos( theta ); | |||||
| position.copy( this.center ).add( offset ); | |||||
| this.object.lookAt( this.center ); | |||||
| thetaDelta /= 1.5; | |||||
| phiDelta /= 1.5; | |||||
| scale = 1; | |||||
| if ( lastPosition.distanceTo( this.object.position ) > 0.01 ) { | |||||
| this.dispatchEvent( changeEvent ); | |||||
| lastPosition.copy( this.object.position ); | |||||
| } | |||||
| }; | |||||
| function getAutoRotationAngle() { | |||||
| return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; | |||||
| } | |||||
| function getZoomScale() { | |||||
| return Math.pow( 0.95, scope.userZoomSpeed ); | |||||
| } | |||||
| function onMouseDown( event ) { | |||||
| if ( scope.enabled === false ) return; | |||||
| if ( scope.userRotate === false ) return; | |||||
| event.preventDefault(); | |||||
| if ( state === STATE.NONE ) | |||||
| { | |||||
| if ( event.button === 0 ) | |||||
| state = STATE.ROTATE; | |||||
| if ( event.button === 1 ) | |||||
| state = STATE.ZOOM; | |||||
| if ( event.button === 2 ) | |||||
| state = STATE.PAN; | |||||
| } | |||||
| if ( state === STATE.ROTATE ) { | |||||
| //state = STATE.ROTATE; | |||||
| rotateStart.set( event.clientX, event.clientY ); | |||||
| } else if ( state === STATE.ZOOM ) { | |||||
| //state = STATE.ZOOM; | |||||
| zoomStart.set( event.clientX, event.clientY ); | |||||
| } else if ( state === STATE.PAN ) { | |||||
| //state = STATE.PAN; | |||||
| } | |||||
| document.addEventListener( 'mousemove', onMouseMove, false ); | |||||
| document.addEventListener( 'mouseup', onMouseUp, false ); | |||||
| } | |||||
| function onMouseMove( event ) { | |||||
| if ( scope.enabled === false ) return; | |||||
| event.preventDefault(); | |||||
| if ( state === STATE.ROTATE ) { | |||||
| rotateEnd.set( event.clientX, event.clientY ); | |||||
| rotateDelta.subVectors( rotateEnd, rotateStart ); | |||||
| scope.rotateLeft( 2 * Math.PI * rotateDelta.x / PIXELS_PER_ROUND * scope.userRotateSpeed ); | |||||
| scope.rotateUp( 2 * Math.PI * rotateDelta.y / PIXELS_PER_ROUND * scope.userRotateSpeed ); | |||||
| rotateStart.copy( rotateEnd ); | |||||
| } else if ( state === STATE.ZOOM ) { | |||||
| zoomEnd.set( event.clientX, event.clientY ); | |||||
| zoomDelta.subVectors( zoomEnd, zoomStart ); | |||||
| if ( zoomDelta.y > 0 ) { | |||||
| scope.zoomIn(); | |||||
| } else { | |||||
| scope.zoomOut(); | |||||
| } | |||||
| zoomStart.copy( zoomEnd ); | |||||
| } else if ( state === STATE.PAN ) { | |||||
| var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0; | |||||
| var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0; | |||||
| scope.pan( new THREE.Vector3( - movementX, movementY, 0 ) ); | |||||
| } | |||||
| } | |||||
| function onMouseUp( event ) { | |||||
| if ( scope.enabled === false ) return; | |||||
| if ( scope.userRotate === false ) return; | |||||
| document.removeEventListener( 'mousemove', onMouseMove, false ); | |||||
| document.removeEventListener( 'mouseup', onMouseUp, false ); | |||||
| state = STATE.NONE; | |||||
| } | |||||
| function onMouseWheel( event ) { | |||||
| if ( scope.enabled === false ) return; | |||||
| if ( scope.userZoom === false ) return; | |||||
| var delta = 0; | |||||
| if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 | |||||
| delta = event.wheelDelta; | |||||
| } else if ( event.detail ) { // Firefox | |||||
| delta = - event.detail; | |||||
| } | |||||
| if ( delta > 0 ) { | |||||
| scope.zoomOut(); | |||||
| } else { | |||||
| scope.zoomIn(); | |||||
| } | |||||
| } | |||||
| function onKeyDown( event ) { | |||||
| if ( scope.enabled === false ) return; | |||||
| if ( scope.userPan === false ) return; | |||||
| switch ( event.keyCode ) { | |||||
| /*case scope.keys.UP: | |||||
| scope.pan( new THREE.Vector3( 0, 1, 0 ) ); | |||||
| break; | |||||
| case scope.keys.BOTTOM: | |||||
| scope.pan( new THREE.Vector3( 0, - 1, 0 ) ); | |||||
| break; | |||||
| case scope.keys.LEFT: | |||||
| scope.pan( new THREE.Vector3( - 1, 0, 0 ) ); | |||||
| break; | |||||
| case scope.keys.RIGHT: | |||||
| scope.pan( new THREE.Vector3( 1, 0, 0 ) ); | |||||
| break; | |||||
| */ | |||||
| case scope.keys.ROTATE: | |||||
| state = STATE.ROTATE; | |||||
| break; | |||||
| case scope.keys.ZOOM: | |||||
| state = STATE.ZOOM; | |||||
| break; | |||||
| case scope.keys.PAN: | |||||
| state = STATE.PAN; | |||||
| break; | |||||
| } | |||||
| } | |||||
| function onKeyUp( event ) { | |||||
| switch ( event.keyCode ) { | |||||
| case scope.keys.ROTATE: | |||||
| case scope.keys.ZOOM: | |||||
| case scope.keys.PAN: | |||||
| state = STATE.NONE; | |||||
| break; | |||||
| } | |||||
| } | |||||
| this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); | |||||
| this.domElement.addEventListener( 'mousedown', onMouseDown, false ); | |||||
| this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); | |||||
| this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox | |||||
| window.addEventListener( 'keydown', onKeyDown, false ); | |||||
| window.addEventListener( 'keyup', onKeyUp, false ); | |||||
| }; | |||||
| THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); | |||||
| @@ -1,36 +0,0 @@ | |||||
| var websocket = {}; | |||||
| websocket.update = undefined; | |||||
| websocket.connect = function(update) { | |||||
| websocket.ws = new WebSocket("ws://localhost:5000"); | |||||
| if (update){ | |||||
| websocket.update = update; | |||||
| } | |||||
| websocket.ws.onopen = function(evt) { | |||||
| gui.serverMessage("Connected to server."); | |||||
| }; | |||||
| websocket.ws.onerror = function(err) { | |||||
| gui.serverMessage("Could not connect to server."); | |||||
| }; | |||||
| websocket.ws.onmessage = function(evt) { | |||||
| json = JSON.parse(evt.data); | |||||
| for (var i in json.node) { | |||||
| var pos = json.node[i].position; | |||||
| json.node[i].position = new THREE.Vector3(pos.x, pos.y, pos.z); | |||||
| if (json.node[i].vop === undefined){ | |||||
| json.node[i].vop = 0; | |||||
| } | |||||
| } | |||||
| websocket.update(json); | |||||
| }; | |||||
| websocket.ws.onclose = function(evt) { | |||||
| gui.serverMessage("No connection to server. <a href='#' onclick='javascript:websocket.connect()'>Reconnect</a>.", true); | |||||
| }; | |||||
| }; | |||||
| websocket.edit = function (data) { | |||||
| websocket.ws.send("edit:"+JSON.stringify(data)); | |||||
| }; | |||||
| @@ -1,35 +0,0 @@ | |||||
| import time, atexit, json | |||||
| import networkx as nx | |||||
| import numpy as np | |||||
| import websocket | |||||
| from socket import error as socket_error | |||||
| from . import clifford | |||||
| from . import util | |||||
| from . import nxgraphstate | |||||
| class VizClient(object): | |||||
| def __init__(self, uri = "ws://localhost:5000"): | |||||
| self.ws = websocket.create_connection(uri, timeout=0.1) | |||||
| atexit.register(self.shutdown) | |||||
| def shutdown(self): | |||||
| """ Close the connection to the websocket """ | |||||
| self.ws.close() | |||||
| def update(self, graph, delay = 0.5): | |||||
| """ Call this function when you are ready to send data to the browser """ | |||||
| g = nxgraphstate.NXGraphState(graph) | |||||
| # Automatically perform layout if position is not provided | |||||
| if not all(("position" in node) for node in list(g.node.values())): | |||||
| g.layout() | |||||
| # Send data to browser and rate-limit | |||||
| try: | |||||
| self.ws.send(json.dumps(g.to_json(stringify=True))) | |||||
| self.ws.recv() | |||||
| except websocket._exceptions.WebSocketTimeoutException: | |||||
| print("Timed out ... you might be pushing a bit hard") | |||||
| time.sleep(delay) | |||||
| @@ -1,105 +0,0 @@ | |||||
| #!/usr/bin/python | |||||
| """ | |||||
| This is a simple websocket relay server that facilitates realtime visualization of GraphStates. | |||||
| It doesn't do much except echo websocket messages to all connected clients, and serve some static content over HTTP. | |||||
| """ | |||||
| from websocket_server import WebsocketServer | |||||
| from SimpleHTTPServer import SimpleHTTPRequestHandler | |||||
| from BaseHTTPServer import HTTPServer | |||||
| from SocketServer import ThreadingMixIn | |||||
| import os, sys, threading | |||||
| import webbrowser | |||||
| import argparse | |||||
| import abp | |||||
| import json | |||||
| from pkg_resources import resource_filename | |||||
| from pprint import pprint | |||||
| import time | |||||
| abp.DETERMINISTIC = True | |||||
| clients = [] | |||||
| local_state = abp.GraphState() | |||||
| def process_edit(edit, client, server): | |||||
| action = edit["action"] | |||||
| print action.upper() | |||||
| for key, value in edit.items(): | |||||
| if key!="action": | |||||
| print " {}: {}".format(key, value) | |||||
| if action == "create": | |||||
| local_state.add_qubit(edit["name"], position=edit["position"], vop=0) | |||||
| elif action == "cz": | |||||
| local_state.act_cz(edit["start"], edit["end"]) | |||||
| elif action == "hadamard": | |||||
| local_state.act_hadamard(edit["node"]) | |||||
| elif action == "phase": | |||||
| local_state.act_local_rotation(edit["node"], "phase") | |||||
| elif action == "delete": | |||||
| local_state._del_node(edit["node"]) | |||||
| elif action == "localcomplementation": | |||||
| local_state.local_complementation(edit["node"]) | |||||
| elif action == "measure": | |||||
| local_state.measure(edit["node"], "p"+edit["basis"]) | |||||
| else: | |||||
| pass | |||||
| #server.send_message(client, json.dumps(local_state.to_json())) | |||||
| server.send_message_to_all(json.dumps(local_state.to_json())) | |||||
| def new_message(client, server, message): | |||||
| if message.startswith("edit:"): | |||||
| edit = json.loads(message[5:]) | |||||
| process_edit(edit, client, server) | |||||
| else: | |||||
| print "Received update from python {}.".format(client["id"]) | |||||
| # print message | |||||
| local_state.from_json(json.loads(message)) | |||||
| # print local_state | |||||
| server.send_message_to_all(message) | |||||
| def new_client(client, server): | |||||
| print "Client {} connected.".format(client["id"]) | |||||
| clients.append(client) | |||||
| print "Sent state of {} nodes to client {}".format(local_state.order(), client["id"]) | |||||
| server.send_message(client, json.dumps(local_state.to_json())) | |||||
| def client_left(client, server): | |||||
| print "Client {} disconnected.".format(client["id"]) | |||||
| clients.remove(client) | |||||
| class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): | |||||
| """ Handle requests in a separate thread """ | |||||
| if __name__ == '__main__': | |||||
| parser = argparse.ArgumentParser(description = "ABP websocket server") | |||||
| parser.add_argument("-v", action="store_true", help="Launch browser") | |||||
| args = parser.parse_args() | |||||
| # Change to the right working dir | |||||
| where = os.path.abspath(resource_filename("abp.static", "")) | |||||
| print "abpserver 0.4.27" | |||||
| print where | |||||
| print "Open http://localhost:5001 in a browser!" | |||||
| os.chdir(where) | |||||
| # Start the HTTP server | |||||
| httpserver = ThreadedHTTPServer(('', 5001), SimpleHTTPRequestHandler) | |||||
| thread = threading.Thread(target = httpserver.serve_forever) | |||||
| thread.daemon = True | |||||
| thread.start() | |||||
| if args.v: | |||||
| webbrowser.open("http://localhost:5001/") | |||||
| # Start the websocket server | |||||
| server = WebsocketServer(5000) | |||||
| server.set_fn_new_client(new_client) | |||||
| server.set_fn_message_received(new_message) | |||||
| server.set_fn_client_left(client_left) | |||||
| server.run_forever() | |||||
| httpserver.shutdown() | |||||
| @@ -2,12 +2,10 @@ from setuptools import setup | |||||
| from glob import glob | from glob import glob | ||||
| from os import path | from os import path | ||||
| STATIC = glob("abp/static/*.*")+glob("abp/static/img/*.*")+glob("abp/static/scripts/*.*") | |||||
| setup( | setup( | ||||
| name = "abp", | name = "abp", | ||||
| version = "0.4.27", | version = "0.4.27", | ||||
| packages = ["abp", "abp.static"], | |||||
| packages = ["abp"], | |||||
| test_suite = "tests", | test_suite = "tests", | ||||
| author = "Pete Shadbolt", | author = "Pete Shadbolt", | ||||
| author_email = "hello@peteshadbolt.co.uk", | author_email = "hello@peteshadbolt.co.uk", | ||||
| @@ -15,8 +13,5 @@ setup( | |||||
| description = "Port of C++ due to Simon Anders and Hans J Briegel", | description = "Port of C++ due to Simon Anders and Hans J Briegel", | ||||
| keywords = "quantum", | keywords = "quantum", | ||||
| setup_requires = ["numpy"], | setup_requires = ["numpy"], | ||||
| scripts = ["bin/abpserver"], | |||||
| install_requires = ["numpy", "networkx", "websocket-client", "websocket-server"], | install_requires = ["numpy", "networkx", "websocket-client", "websocket-server"], | ||||
| package_data = {"abp.static": STATIC}, | |||||
| include_package_data=True | |||||
| ) | ) | ||||