1// Copyright 2021 The Cirq Developers 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import { 16 Vector3, 17 Line, 18 LineBasicMaterial, 19 BufferGeometry, 20 Texture, 21 SpriteMaterial, 22 Sprite, 23 Mesh, 24 MeshBasicMaterial, 25 SphereGeometry, 26 CylinderGeometry, 27 DoubleSide, 28 BoxGeometry, 29 Group, 30} from 'three'; 31 32/** 33 * A wrapper for a three.js Line object representing a connection line 34 * between two qubits. Useful when building controlled gates. 35 */ 36export class ConnectionLine extends Line { 37 /** 38 * Class constructor. 39 * @param startCoord The starting coordinate of the line 40 * @param endCoord The ending coordinate of the line 41 * @returns a CollectionLine object that can be added to a three.js scene 42 */ 43 constructor(startCoord: Vector3, endCoord: Vector3) { 44 const COLOR = 'black'; 45 46 const material = new LineBasicMaterial({color: COLOR}); 47 const points = [startCoord, endCoord]; 48 const geometry = new BufferGeometry().setFromPoints(points); 49 50 super(geometry, material); 51 return this; 52 } 53} 54 55/** 56 * A wrapper for a three.js Sprite object which is used to label the 57 * location of specific qubits. 58 */ 59export class QubitLabel extends Sprite { 60 readonly text: string; 61 /** 62 * Class constructor. 63 * @param text The text which the label should display 64 * @returns a QubitLabel object that can be added to a three.js scene 65 */ 66 constructor(text: string) { 67 const CANVAS_SIZE = 128; 68 69 const canvas = document.createElement('canvas'); 70 canvas.width = CANVAS_SIZE; 71 canvas.height = CANVAS_SIZE; 72 // Allows us to keep track of what we're adding to the 73 // canvas. 74 canvas.textContent = text; 75 76 const context = canvas.getContext('2d')!; 77 context.fillStyle = '#000000'; 78 context.textAlign = 'center'; 79 context.font = '20px Arial'; 80 context.fillText(text, CANVAS_SIZE / 2, CANVAS_SIZE / 2); 81 82 const map = new Texture(canvas); 83 map.needsUpdate = true; 84 85 const material = new SpriteMaterial({ 86 map, 87 transparent: true, // for a transparent canvas background 88 }); 89 90 super(material); 91 this.text = text; 92 return this; 93 } 94} 95 96/** 97 * A wrapper for a three.js Line object which represents a qubit in 98 * this circuit. 99 */ 100export class QubitLine extends Line { 101 /** 102 * Class constructor. 103 * @param startCoord The starting coordinate of the line 104 * @param endCoord The ending coordinate of the line 105 * @returns a QubitLine object that can be added to a three.js scene. 106 */ 107 constructor(startCoord: Vector3, endCoord: Vector3) { 108 const COLOR = 'gray'; 109 110 const material = new LineBasicMaterial({color: COLOR}); 111 const points = [startCoord, endCoord]; 112 const geometry = new BufferGeometry().setFromPoints(points); 113 114 super(geometry, material); 115 return this; 116 } 117} 118 119/** 120 * A wrapper for a three.js Sphere which represents a control 121 * in a circuit. 122 */ 123export class Control3DSymbol extends Mesh { 124 /** 125 * Class constructor. 126 * @returns a Control3DSymbol object that can be added to a three.js scene. 127 */ 128 constructor() { 129 const COLOR = 'black'; 130 131 const material = new MeshBasicMaterial({color: COLOR}); 132 const geometry = new SphereGeometry(0.1, 32, 32); 133 134 super(geometry, material); 135 return this; 136 } 137} 138 139/** 140 * A wrapper for a three.js Group which represents an X operation 141 * in a circuit. 142 */ 143export class X3DSymbol extends Group { 144 /** 145 * Class constructor. 146 * @param color The color of the symbol 147 * @returns an X3DSymbol object that can be added to a three.js scene 148 */ 149 constructor(color: string) { 150 super(); 151 const material = new MeshBasicMaterial({color: color, side: DoubleSide}); 152 const geometry = new CylinderGeometry( 153 0.3, 154 0.3, 155 0.1, 156 32, 157 1, 158 true, 159 0, 160 2 * Math.PI 161 ); 162 const hollowCylinder = new Mesh(geometry, material); 163 this.add(hollowCylinder); 164 165 // Creates the "X" in the middle of the holow cylinder 166 const rotationAngle = Math.PI / 2; 167 168 const xLineMaterial = new MeshBasicMaterial({color: color}); 169 const xLineGeometry = new CylinderGeometry(0.01, 0.01, 0.6); 170 const xLine = new Mesh(xLineGeometry, xLineMaterial); 171 xLine.rotation.x = rotationAngle; 172 173 const zLineMaterial = new MeshBasicMaterial({color: color}); 174 const zLineGeometry = new CylinderGeometry(0.01, 0.01, 0.6); 175 const zLine = new Mesh(zLineGeometry, zLineMaterial); 176 zLine.rotation.z = rotationAngle; 177 178 this.add(xLine); 179 this.add(zLine); 180 return this; 181 } 182} 183 184/** 185 * A wrapper for a three.js Group which represents an Swap operation 186 * in a circuit. 187 */ 188export class Swap3DSymbol extends Group { 189 /** 190 * Class constructor. 191 * @returns a Swap3DSymbol object that can be added to a three.js scene 192 */ 193 constructor() { 194 super(); 195 196 const xLineMaterial = new MeshBasicMaterial({color: 'black'}); 197 const xLineGeometry = new CylinderGeometry(0.01, 0.01, 0.3); 198 const xLine = new Mesh(xLineGeometry, xLineMaterial); 199 xLine.rotation.x = Math.PI / 2; 200 xLine.rotation.z = (3 * Math.PI) / 4; 201 202 const zLineMaterial = new MeshBasicMaterial({color: 'black'}); 203 const zLineGeometry = new CylinderGeometry(0.01, 0.01, 0.3); 204 const zLine = new Mesh(zLineGeometry, zLineMaterial); 205 zLine.rotation.x = Math.PI / 2; 206 zLine.rotation.z = Math.PI / 4; 207 208 this.add(xLine); 209 this.add(zLine); 210 return this; 211 } 212} 213 214/** 215 * A wrapper for a three.js Box which represents arbitrary single qubit 216 * operations in a circuit 217 */ 218export class BoxGate3DSymbol extends Mesh { 219 /** 220 * Class constructor. 221 * @param label The label that will go on the three.js box 222 * @param color The color of the box 223 * @returns a BoxGate3DSymbol object that can be added to a three.js scene 224 */ 225 constructor(label: string, color: string) { 226 const canvas = document.createElement('canvas')!; 227 const context = canvas.getContext('2d')!; 228 canvas.width = canvas.height = 128; 229 230 context.fillStyle = color; 231 context.fillRect(0, 0, canvas.width, canvas.height); 232 233 let fontSize = 60; 234 let textWidth; 235 do { 236 fontSize /= 1.2; 237 context.font = `${fontSize}pt arial bold`; 238 textWidth = context.measureText(label).width; 239 } while (textWidth > canvas.width); 240 241 context.fillStyle = 'black'; 242 context.fillText( 243 label, 244 canvas.width / 2 - textWidth / 2, 245 canvas.height / 2 + fontSize / 2 246 ); 247 248 const map = new Texture(canvas); 249 map.needsUpdate = true; 250 251 const geometry = new BoxGeometry(0.5, 0.5, 0.5); 252 const material = new MeshBasicMaterial({map: map, color: color}); 253 254 super(geometry, material); 255 return this; 256 } 257} 258