| @@ -0,0 +1,32 @@ | |||||
| from flask import Flask, request, redirect, url_for, make_response, render_template, Markup, send_from_directory, send_file | |||||
| from flask_redis import FlaskRedis | |||||
| import json, abp | |||||
| app = Flask(__name__) | |||||
| redis = FlaskRedis(app) | |||||
| @app.route("/") | |||||
| def index(): | |||||
| return render_template("index.html") | |||||
| @app.route("/graph", methods=["GET", "POST"]) | |||||
| def graph(page): | |||||
| if request.method == 'POST': | |||||
| # Convert the data to a graph state | |||||
| g = abp.GraphState() | |||||
| g.from_json(json.loads(data)) | |||||
| # Convert it back to JSON | |||||
| data = json.dumps(g.to_json(stringify=True)) | |||||
| # Insert into the database | |||||
| redis.execute_command("SET", "graph", data) | |||||
| # Return success | |||||
| return "OK" | |||||
| else: | |||||
| # Get from the database | |||||
| return redis.get("graph") | |||||
| @@ -0,0 +1,91 @@ | |||||
| <?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> | |||||
| @@ -0,0 +1,91 @@ | |||||
| <?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> | |||||
| @@ -0,0 +1,92 @@ | |||||
| 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; | |||||
| } | |||||
| #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; | |||||
| } | |||||
| @@ -0,0 +1 @@ | |||||
| qcengine | |||||
| @@ -0,0 +1,73 @@ | |||||
| 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; | |||||
| }; | |||||
| @@ -0,0 +1,190 @@ | |||||
| 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 + "."); | |||||
| }; | |||||
| @@ -0,0 +1,76 @@ | |||||
| 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(); | |||||
| }; | |||||
| @@ -0,0 +1,80 @@ | |||||
| 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); | |||||
| }; | |||||
| @@ -0,0 +1,58 @@ | |||||
| 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); | |||||
| }; | |||||
| @@ -0,0 +1,10 @@ | |||||
| console.log("abp v0.4.27"); | |||||
| window.onload = function() { | |||||
| graph.prepare(); | |||||
| materials.prepare(); | |||||
| gui.prepare(); | |||||
| mouse.prepare(); | |||||
| editor.prepare(); | |||||
| gui.loop(); | |||||
| }; | |||||
| @@ -0,0 +1,38 @@ | |||||
| 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: 3 | |||||
| }); | |||||
| 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); | |||||
| }; | |||||
| @@ -0,0 +1,73 @@ | |||||
| 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(); | |||||
| } | |||||
| }; | |||||
| @@ -0,0 +1,412 @@ | |||||
| // 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 ); | |||||
| @@ -0,0 +1,36 @@ | |||||
| 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)); | |||||
| }; | |||||
| @@ -0,0 +1,47 @@ | |||||
| <!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="{{ url_for("static", filename="main.css") }}"> | |||||
| <script src="{{ url_for("static", filename="scripts/three.js") }}"></script> | |||||
| <script src="{{ url_for("static", filename="scripts/orbitcontrols.js") }}"></script> | |||||
| <script src="{{ url_for("static", filename="scripts/anders_briegel.js") }}"></script> | |||||
| <script src="{{ url_for("static", filename="scripts/mouse.js") }}"></script> | |||||
| <script src="{{ url_for("static", filename="scripts/materials.js") }}"></script> | |||||
| <script src="{{ url_for("static", filename="scripts/graph.js") }}"></script> | |||||
| <script src="{{ url_for("static", filename="scripts/gui.js") }}"></script> | |||||
| <script src="{{ url_for("static", filename="scripts/editor.js") }}"></script> | |||||
| <script src="{{ url_for("static", filename="scripts/websocket.js") }}"></script> | |||||
| <script src="{{ url_for("static", filename="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> | |||||