├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── Adafruit_BNO055 ├── BNO055.py └── __init__.py ├── LICENSE ├── README.md ├── examples ├── simpletest.py └── webgl_demo │ ├── server.py │ ├── static │ ├── bunny.mtl │ ├── bunny.obj │ ├── cat-top.stl │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ └── js │ │ ├── DDSLoader.js │ │ ├── MTLLoader.js │ │ ├── OBJLoader.js │ │ ├── OBJMTLLoader.js │ │ ├── STLLoader.js │ │ ├── bootstrap.min.js │ │ ├── jquery-2.1.4.min.js │ │ └── three.min.js │ └── templates │ └── index.html ├── ez_setup.py └── setup.py /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for opening an issue on an Adafruit Python library repository. To 2 | improve the speed of resolution please review the following guidelines and 3 | common troubleshooting steps below before creating the issue: 4 | 5 | - **Do not use GitHub issues for troubleshooting projects and issues.** Instead use 6 | the forums at http://forums.adafruit.com to ask questions and troubleshoot why 7 | something isn't working as expected. In many cases the problem is a common issue 8 | that you will more quickly receive help from the forum community. GitHub issues 9 | are meant for known defects in the code. If you don't know if there is a defect 10 | in the code then start with troubleshooting on the forum first. 11 | 12 | - **If following a tutorial or guide be sure you didn't miss a step.** Carefully 13 | check all of the steps and commands to run have been followed. Consult the 14 | forum if you're unsure or have questions about steps in a guide/tutorial. 15 | 16 | - **For Python/Raspberry Pi projects check these very common issues to ensure they don't apply**: 17 | 18 | - If you are receiving an **ImportError: No module named...** error then a 19 | library the code depends on is not installed. Check the tutorial/guide or 20 | README to ensure you have installed the necessary libraries. Usually the 21 | missing library can be installed with the `pip` tool, but check the tutorial/guide 22 | for the exact command. 23 | 24 | - **Be sure you are supplying adequate power to the board.** Check the specs of 25 | your board and power in an external power supply. In many cases just 26 | plugging a board into your computer is not enough to power it and other 27 | peripherals. 28 | 29 | - **Double check all soldering joints and connections.** Flakey connections 30 | cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. 31 | 32 | If you're sure this issue is a defect in the code and checked the steps above 33 | please fill in the following fields to provide enough troubleshooting information. 34 | You may delete the guideline and text above to just leave the following details: 35 | 36 | - Platform/operating system (i.e. Raspberry Pi with Raspbian operating system, 37 | Windows 32-bit, Windows 64-bit, Mac OSX 64-bit, etc.): **INSERT PLATFORM/OPERATING 38 | SYSTEM HERE** 39 | 40 | - Python version (run `python -version` or `python3 -version`): **INSERT PYTHON 41 | VERSION HERE** 42 | 43 | - Error message you are receiving, including any Python exception traces: **INSERT 44 | ERROR MESAGE/EXCEPTION TRACES HERE*** 45 | 46 | - List the steps to reproduce the problem below (if possible attach code or commands 47 | to run): **LIST REPRO STEPS BELOW** 48 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for creating a pull request to contribute to Adafruit's GitHub code! 2 | Before you open the request please review the following guidelines and tips to 3 | help it be more easily integrated: 4 | 5 | - **Describe the scope of your change--i.e. what the change does and what parts 6 | of the code were modified.** This will help us understand any risks of integrating 7 | the code. 8 | 9 | - **Describe any known limitations with your change.** For example if the change 10 | doesn't apply to a supported platform of the library please mention it. 11 | 12 | - **Please run any tests or examples that can exercise your modified code.** We 13 | strive to not break users of the code and running tests/examples helps with this 14 | process. 15 | 16 | Thank you again for contributing! We will try to test and integrate the change 17 | as soon as we can, but be aware we have many GitHub repositories to manage and 18 | can't immediately respond to every request. There is no need to bump or check in 19 | on a pull request (it will clutter the discussion of the request). 20 | 21 | Also don't be worried if the request is closed or not integrated--sometimes the 22 | priorities of Adafruit's GitHub code (education, ease of use) might not match the 23 | priorities of the pull request. Don't fret, the open source community thrives on 24 | forks and GitHub makes it easy to keep your changes in a forked repo. 25 | 26 | After reviewing the guidelines above you can delete this text from the pull request. 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | calibration.json 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | 47 | # Translations 48 | *.mo 49 | *.pot 50 | 51 | # Django stuff: 52 | *.log 53 | 54 | # Sphinx documentation 55 | docs/_build/ 56 | 57 | # PyBuilder 58 | target/ 59 | -------------------------------------------------------------------------------- /Adafruit_BNO055/BNO055.py: -------------------------------------------------------------------------------- 1 | # Adafruit BNO055 Absolute Orientation Sensor Library 2 | # Copyright (c) 2015 Adafruit Industries 3 | # Author: Tony DiCola 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | import binascii 23 | import logging 24 | import struct 25 | import time 26 | 27 | import serial 28 | 29 | 30 | # I2C addresses 31 | BNO055_ADDRESS_A = 0x28 32 | BNO055_ADDRESS_B = 0x29 33 | BNO055_ID = 0xA0 34 | 35 | # Page id register definition 36 | BNO055_PAGE_ID_ADDR = 0X07 37 | 38 | # PAGE0 REGISTER DEFINITION START 39 | BNO055_CHIP_ID_ADDR = 0x00 40 | BNO055_ACCEL_REV_ID_ADDR = 0x01 41 | BNO055_MAG_REV_ID_ADDR = 0x02 42 | BNO055_GYRO_REV_ID_ADDR = 0x03 43 | BNO055_SW_REV_ID_LSB_ADDR = 0x04 44 | BNO055_SW_REV_ID_MSB_ADDR = 0x05 45 | BNO055_BL_REV_ID_ADDR = 0X06 46 | 47 | # Accel data register 48 | BNO055_ACCEL_DATA_X_LSB_ADDR = 0X08 49 | BNO055_ACCEL_DATA_X_MSB_ADDR = 0X09 50 | BNO055_ACCEL_DATA_Y_LSB_ADDR = 0X0A 51 | BNO055_ACCEL_DATA_Y_MSB_ADDR = 0X0B 52 | BNO055_ACCEL_DATA_Z_LSB_ADDR = 0X0C 53 | BNO055_ACCEL_DATA_Z_MSB_ADDR = 0X0D 54 | 55 | # Mag data register 56 | BNO055_MAG_DATA_X_LSB_ADDR = 0X0E 57 | BNO055_MAG_DATA_X_MSB_ADDR = 0X0F 58 | BNO055_MAG_DATA_Y_LSB_ADDR = 0X10 59 | BNO055_MAG_DATA_Y_MSB_ADDR = 0X11 60 | BNO055_MAG_DATA_Z_LSB_ADDR = 0X12 61 | BNO055_MAG_DATA_Z_MSB_ADDR = 0X13 62 | 63 | # Gyro data registers 64 | BNO055_GYRO_DATA_X_LSB_ADDR = 0X14 65 | BNO055_GYRO_DATA_X_MSB_ADDR = 0X15 66 | BNO055_GYRO_DATA_Y_LSB_ADDR = 0X16 67 | BNO055_GYRO_DATA_Y_MSB_ADDR = 0X17 68 | BNO055_GYRO_DATA_Z_LSB_ADDR = 0X18 69 | BNO055_GYRO_DATA_Z_MSB_ADDR = 0X19 70 | 71 | # Euler data registers 72 | BNO055_EULER_H_LSB_ADDR = 0X1A 73 | BNO055_EULER_H_MSB_ADDR = 0X1B 74 | BNO055_EULER_R_LSB_ADDR = 0X1C 75 | BNO055_EULER_R_MSB_ADDR = 0X1D 76 | BNO055_EULER_P_LSB_ADDR = 0X1E 77 | BNO055_EULER_P_MSB_ADDR = 0X1F 78 | 79 | # Quaternion data registers 80 | BNO055_QUATERNION_DATA_W_LSB_ADDR = 0X20 81 | BNO055_QUATERNION_DATA_W_MSB_ADDR = 0X21 82 | BNO055_QUATERNION_DATA_X_LSB_ADDR = 0X22 83 | BNO055_QUATERNION_DATA_X_MSB_ADDR = 0X23 84 | BNO055_QUATERNION_DATA_Y_LSB_ADDR = 0X24 85 | BNO055_QUATERNION_DATA_Y_MSB_ADDR = 0X25 86 | BNO055_QUATERNION_DATA_Z_LSB_ADDR = 0X26 87 | BNO055_QUATERNION_DATA_Z_MSB_ADDR = 0X27 88 | 89 | # Linear acceleration data registers 90 | BNO055_LINEAR_ACCEL_DATA_X_LSB_ADDR = 0X28 91 | BNO055_LINEAR_ACCEL_DATA_X_MSB_ADDR = 0X29 92 | BNO055_LINEAR_ACCEL_DATA_Y_LSB_ADDR = 0X2A 93 | BNO055_LINEAR_ACCEL_DATA_Y_MSB_ADDR = 0X2B 94 | BNO055_LINEAR_ACCEL_DATA_Z_LSB_ADDR = 0X2C 95 | BNO055_LINEAR_ACCEL_DATA_Z_MSB_ADDR = 0X2D 96 | 97 | # Gravity data registers 98 | BNO055_GRAVITY_DATA_X_LSB_ADDR = 0X2E 99 | BNO055_GRAVITY_DATA_X_MSB_ADDR = 0X2F 100 | BNO055_GRAVITY_DATA_Y_LSB_ADDR = 0X30 101 | BNO055_GRAVITY_DATA_Y_MSB_ADDR = 0X31 102 | BNO055_GRAVITY_DATA_Z_LSB_ADDR = 0X32 103 | BNO055_GRAVITY_DATA_Z_MSB_ADDR = 0X33 104 | 105 | # Temperature data register 106 | BNO055_TEMP_ADDR = 0X34 107 | 108 | # Status registers 109 | BNO055_CALIB_STAT_ADDR = 0X35 110 | BNO055_SELFTEST_RESULT_ADDR = 0X36 111 | BNO055_INTR_STAT_ADDR = 0X37 112 | 113 | BNO055_SYS_CLK_STAT_ADDR = 0X38 114 | BNO055_SYS_STAT_ADDR = 0X39 115 | BNO055_SYS_ERR_ADDR = 0X3A 116 | 117 | # Unit selection register 118 | BNO055_UNIT_SEL_ADDR = 0X3B 119 | BNO055_DATA_SELECT_ADDR = 0X3C 120 | 121 | # Mode registers 122 | BNO055_OPR_MODE_ADDR = 0X3D 123 | BNO055_PWR_MODE_ADDR = 0X3E 124 | 125 | BNO055_SYS_TRIGGER_ADDR = 0X3F 126 | BNO055_TEMP_SOURCE_ADDR = 0X40 127 | 128 | # Axis remap registers 129 | BNO055_AXIS_MAP_CONFIG_ADDR = 0X41 130 | BNO055_AXIS_MAP_SIGN_ADDR = 0X42 131 | 132 | # Axis remap values 133 | AXIS_REMAP_X = 0x00 134 | AXIS_REMAP_Y = 0x01 135 | AXIS_REMAP_Z = 0x02 136 | AXIS_REMAP_POSITIVE = 0x00 137 | AXIS_REMAP_NEGATIVE = 0x01 138 | 139 | # SIC registers 140 | BNO055_SIC_MATRIX_0_LSB_ADDR = 0X43 141 | BNO055_SIC_MATRIX_0_MSB_ADDR = 0X44 142 | BNO055_SIC_MATRIX_1_LSB_ADDR = 0X45 143 | BNO055_SIC_MATRIX_1_MSB_ADDR = 0X46 144 | BNO055_SIC_MATRIX_2_LSB_ADDR = 0X47 145 | BNO055_SIC_MATRIX_2_MSB_ADDR = 0X48 146 | BNO055_SIC_MATRIX_3_LSB_ADDR = 0X49 147 | BNO055_SIC_MATRIX_3_MSB_ADDR = 0X4A 148 | BNO055_SIC_MATRIX_4_LSB_ADDR = 0X4B 149 | BNO055_SIC_MATRIX_4_MSB_ADDR = 0X4C 150 | BNO055_SIC_MATRIX_5_LSB_ADDR = 0X4D 151 | BNO055_SIC_MATRIX_5_MSB_ADDR = 0X4E 152 | BNO055_SIC_MATRIX_6_LSB_ADDR = 0X4F 153 | BNO055_SIC_MATRIX_6_MSB_ADDR = 0X50 154 | BNO055_SIC_MATRIX_7_LSB_ADDR = 0X51 155 | BNO055_SIC_MATRIX_7_MSB_ADDR = 0X52 156 | BNO055_SIC_MATRIX_8_LSB_ADDR = 0X53 157 | BNO055_SIC_MATRIX_8_MSB_ADDR = 0X54 158 | 159 | # Accelerometer Offset registers 160 | ACCEL_OFFSET_X_LSB_ADDR = 0X55 161 | ACCEL_OFFSET_X_MSB_ADDR = 0X56 162 | ACCEL_OFFSET_Y_LSB_ADDR = 0X57 163 | ACCEL_OFFSET_Y_MSB_ADDR = 0X58 164 | ACCEL_OFFSET_Z_LSB_ADDR = 0X59 165 | ACCEL_OFFSET_Z_MSB_ADDR = 0X5A 166 | 167 | # Magnetometer Offset registers 168 | MAG_OFFSET_X_LSB_ADDR = 0X5B 169 | MAG_OFFSET_X_MSB_ADDR = 0X5C 170 | MAG_OFFSET_Y_LSB_ADDR = 0X5D 171 | MAG_OFFSET_Y_MSB_ADDR = 0X5E 172 | MAG_OFFSET_Z_LSB_ADDR = 0X5F 173 | MAG_OFFSET_Z_MSB_ADDR = 0X60 174 | 175 | # Gyroscope Offset register s 176 | GYRO_OFFSET_X_LSB_ADDR = 0X61 177 | GYRO_OFFSET_X_MSB_ADDR = 0X62 178 | GYRO_OFFSET_Y_LSB_ADDR = 0X63 179 | GYRO_OFFSET_Y_MSB_ADDR = 0X64 180 | GYRO_OFFSET_Z_LSB_ADDR = 0X65 181 | GYRO_OFFSET_Z_MSB_ADDR = 0X66 182 | 183 | # Radius registers 184 | ACCEL_RADIUS_LSB_ADDR = 0X67 185 | ACCEL_RADIUS_MSB_ADDR = 0X68 186 | MAG_RADIUS_LSB_ADDR = 0X69 187 | MAG_RADIUS_MSB_ADDR = 0X6A 188 | 189 | # Power modes 190 | POWER_MODE_NORMAL = 0X00 191 | POWER_MODE_LOWPOWER = 0X01 192 | POWER_MODE_SUSPEND = 0X02 193 | 194 | # Operation mode settings 195 | OPERATION_MODE_CONFIG = 0X00 196 | OPERATION_MODE_ACCONLY = 0X01 197 | OPERATION_MODE_MAGONLY = 0X02 198 | OPERATION_MODE_GYRONLY = 0X03 199 | OPERATION_MODE_ACCMAG = 0X04 200 | OPERATION_MODE_ACCGYRO = 0X05 201 | OPERATION_MODE_MAGGYRO = 0X06 202 | OPERATION_MODE_AMG = 0X07 203 | OPERATION_MODE_IMUPLUS = 0X08 204 | OPERATION_MODE_COMPASS = 0X09 205 | OPERATION_MODE_M4G = 0X0A 206 | OPERATION_MODE_NDOF_FMC_OFF = 0X0B 207 | OPERATION_MODE_NDOF = 0X0C 208 | 209 | 210 | logger = logging.getLogger(__name__) 211 | 212 | 213 | class BNO055(object): 214 | 215 | def __init__(self, rst=None, address=BNO055_ADDRESS_A, i2c=None, gpio=None, 216 | serial_port=None, serial_timeout_sec=5, **kwargs): 217 | # If reset pin is provided save it and a reference to provided GPIO 218 | # bus (or the default system GPIO bus if none is provided). 219 | self._rst = rst 220 | if self._rst is not None: 221 | if gpio is None: 222 | import Adafruit_GPIO as GPIO 223 | gpio = GPIO.get_platform_gpio() 224 | self._gpio = gpio 225 | # Setup the reset pin as an output at a high level. 226 | self._gpio.setup(self._rst, GPIO.OUT) 227 | self._gpio.set_high(self._rst) 228 | # Wait a 650 milliseconds in case setting the reset high reset the chip. 229 | time.sleep(0.65) 230 | self._serial = None 231 | self._i2c_device = None 232 | if serial_port is not None: 233 | # Use serial communication if serial_port name is provided. 234 | # Open the serial port at 115200 baud, 8N1. Add a 5 second timeout 235 | # to prevent hanging if device is disconnected. 236 | self._serial = serial.Serial(serial_port, 115200, timeout=serial_timeout_sec, 237 | writeTimeout=serial_timeout_sec) 238 | else: 239 | # Use I2C if no serial port is provided. 240 | # Assume we're using platform's default I2C bus if none is specified. 241 | if i2c is None: 242 | import Adafruit_GPIO.I2C as I2C 243 | i2c = I2C 244 | # Save a reference to the I2C device instance for later communication. 245 | self._i2c_device = i2c.get_i2c_device(address, **kwargs) 246 | 247 | def _serial_send(self, command, ack=True, max_attempts=5): 248 | # Send a serial command and automatically handle if it needs to be resent 249 | # because of a bus error. If ack is True then an ackowledgement is 250 | # expected and only up to the maximum specified attempts will be made 251 | # to get a good acknowledgement (default is 5). If ack is False then 252 | # no acknowledgement is expected (like when resetting the device). 253 | attempts = 0 254 | while True: 255 | # Flush any pending received data to get into a clean state. 256 | self._serial.flushInput() 257 | # Send the data. 258 | self._serial.write(command) 259 | logger.debug('Serial send: 0x{0}'.format(binascii.hexlify(command))) 260 | # Stop if no acknowledgment is expected. 261 | if not ack: 262 | return 263 | # Read acknowledgement response (2 bytes). 264 | resp = bytearray(self._serial.read(2)) 265 | logger.debug('Serial receive: 0x{0}'.format(binascii.hexlify(resp))) 266 | if resp is None or len(resp) != 2: 267 | raise RuntimeError('Timeout waiting for serial acknowledge, is the BNO055 connected?') 268 | # Stop if there's no bus error (0xEE07 response) and return response bytes. 269 | if not (resp[0] == 0xEE and resp[1] == 0x07): 270 | return resp 271 | # Else there was a bus error so resend, as recommended in UART app 272 | # note at: 273 | # http://ae-bst.resource.bosch.com/media/products/dokumente/bno055/BST-BNO055-AN012-00.pdf 274 | attempts += 1 275 | if attempts >= max_attempts: 276 | raise RuntimeError('Exceeded maximum attempts to acknowledge serial command without bus error!') 277 | 278 | def _write_bytes(self, address, data, ack=True): 279 | # Write a list of 8-bit values starting at the provided register address. 280 | if self._i2c_device is not None: 281 | # I2C write. 282 | self._i2c_device.writeList(address, data) 283 | else: 284 | # Build and send serial register write command. 285 | command = bytearray(4+len(data)) 286 | command[0] = 0xAA # Start byte 287 | command[1] = 0x00 # Write 288 | command[2] = address & 0xFF 289 | command[3] = len(data) & 0xFF 290 | command[4:] = map(lambda x: x & 0xFF, data) 291 | resp = self._serial_send(command, ack=ack) 292 | # Verify register write succeeded if there was an acknowledgement. 293 | if resp[0] != 0xEE and resp[1] != 0x01: 294 | raise RuntimeError('Register write error: 0x{0}'.format(binascii.hexlify(resp))) 295 | 296 | def _write_byte(self, address, value, ack=True): 297 | # Write an 8-bit value to the provided register address. If ack is True 298 | # then expect an acknowledgement in serial mode, otherwise ignore any 299 | # acknowledgement (necessary when resetting the device). 300 | if self._i2c_device is not None: 301 | # I2C write. 302 | self._i2c_device.write8(address, value) 303 | else: 304 | # Build and send serial register write command. 305 | command = bytearray(5) 306 | command[0] = 0xAA # Start byte 307 | command[1] = 0x00 # Write 308 | command[2] = address & 0xFF 309 | command[3] = 1 # Length (1 byte) 310 | command[4] = value & 0xFF 311 | resp = self._serial_send(command, ack=ack) 312 | # Verify register write succeeded if there was an acknowledgement. 313 | if ack and resp[0] != 0xEE and resp[1] != 0x01: 314 | raise RuntimeError('Register write error: 0x{0}'.format(binascii.hexlify(resp))) 315 | 316 | def _read_bytes(self, address, length): 317 | # Read a number of unsigned byte values starting from the provided address. 318 | if self._i2c_device is not None: 319 | # I2C read. 320 | return bytearray(self._i2c_device.readList(address, length)) 321 | else: 322 | # Build and send serial register read command. 323 | command = bytearray(4) 324 | command[0] = 0xAA # Start byte 325 | command[1] = 0x01 # Read 326 | command[2] = address & 0xFF 327 | command[3] = length & 0xFF 328 | resp = self._serial_send(command) 329 | # Verify register read succeeded. 330 | if resp[0] != 0xBB: 331 | raise RuntimeError('Register read error: 0x{0}'.format(binascii.hexlify(resp))) 332 | # Read the returned bytes. 333 | length = resp[1] 334 | resp = bytearray(self._serial.read(length)) 335 | logger.debug('Received: 0x{0}'.format(binascii.hexlify(resp))) 336 | if resp is None or len(resp) != length: 337 | raise RuntimeError('Timeout waiting to read data, is the BNO055 connected?') 338 | return resp 339 | 340 | def _read_byte(self, address): 341 | # Read an 8-bit unsigned value from the provided register address. 342 | if self._i2c_device is not None: 343 | # I2C read. 344 | return self._i2c_device.readU8(address) 345 | else: 346 | return self._read_bytes(address, 1)[0] 347 | 348 | def _read_signed_byte(self, address): 349 | # Read an 8-bit signed value from the provided register address. 350 | data = self._read_byte(address) 351 | if data > 127: 352 | return data - 256 353 | else: 354 | return data 355 | 356 | def _config_mode(self): 357 | # Enter configuration mode. 358 | self.set_mode(OPERATION_MODE_CONFIG) 359 | 360 | def _operation_mode(self): 361 | # Enter operation mode to read sensor data. 362 | self.set_mode(self._mode) 363 | 364 | def begin(self, mode=OPERATION_MODE_NDOF): 365 | """Initialize the BNO055 sensor. Must be called once before any other 366 | BNO055 library functions. Will return True if the BNO055 was 367 | successfully initialized, and False otherwise. 368 | """ 369 | # Save the desired normal operation mode. 370 | self._mode = mode 371 | # First send a thow-away command and ignore any response or I2C errors 372 | # just to make sure the BNO is in a good state and ready to accept 373 | # commands (this seems to be necessary after a hard power down). 374 | try: 375 | self._write_byte(BNO055_PAGE_ID_ADDR, 0, ack=False) 376 | except IOError: 377 | # Swallow an IOError that might be raised by an I2C issue. Only do 378 | # this for this very first command to help get the BNO and board's 379 | # I2C into a clear state ready to accept the next commands. 380 | pass 381 | # Make sure we're in config mode and on page 0. 382 | self._config_mode() 383 | self._write_byte(BNO055_PAGE_ID_ADDR, 0) 384 | # Check the chip ID 385 | bno_id = self._read_byte(BNO055_CHIP_ID_ADDR) 386 | logger.debug('Read chip ID: 0x{0:02X}'.format(bno_id)) 387 | if bno_id != BNO055_ID: 388 | return False 389 | # Reset the device. 390 | if self._rst is not None: 391 | # Use the hardware reset pin if provided. 392 | # Go low for a short period, then high to signal a reset. 393 | self._gpio.set_low(self._rst) 394 | time.sleep(0.01) # 10ms 395 | self._gpio.set_high(self._rst) 396 | else: 397 | # Else use the reset command. Note that ack=False is sent because 398 | # the chip doesn't seem to ack a reset in serial mode (by design?). 399 | self._write_byte(BNO055_SYS_TRIGGER_ADDR, 0x20, ack=False) 400 | # Wait 650ms after reset for chip to be ready (as suggested 401 | # in datasheet). 402 | time.sleep(0.65) 403 | # Set to normal power mode. 404 | self._write_byte(BNO055_PWR_MODE_ADDR, POWER_MODE_NORMAL) 405 | # Default to internal oscillator. 406 | self._write_byte(BNO055_SYS_TRIGGER_ADDR, 0x0) 407 | # Enter normal operation mode. 408 | self._operation_mode() 409 | return True 410 | 411 | def set_mode(self, mode): 412 | """Set operation mode for BNO055 sensor. Mode should be a value from 413 | table 3-3 and 3-5 of the datasheet: 414 | http://www.adafruit.com/datasheets/BST_BNO055_DS000_12.pdf 415 | """ 416 | self._write_byte(BNO055_OPR_MODE_ADDR, mode & 0xFF) 417 | # Delay for 30 milliseconds (datsheet recommends 19ms, but a little more 418 | # can't hurt and the kernel is going to spend some unknown amount of time 419 | # too). 420 | time.sleep(0.03) 421 | 422 | def get_revision(self): 423 | """Return a tuple with revision information about the BNO055 chip. Will 424 | return 5 values: 425 | - Software revision 426 | - Bootloader version 427 | - Accelerometer ID 428 | - Magnetometer ID 429 | - Gyro ID 430 | """ 431 | # Read revision values. 432 | accel = self._read_byte(BNO055_ACCEL_REV_ID_ADDR) 433 | mag = self._read_byte(BNO055_MAG_REV_ID_ADDR) 434 | gyro = self._read_byte(BNO055_GYRO_REV_ID_ADDR) 435 | bl = self._read_byte(BNO055_BL_REV_ID_ADDR) 436 | sw_lsb = self._read_byte(BNO055_SW_REV_ID_LSB_ADDR) 437 | sw_msb = self._read_byte(BNO055_SW_REV_ID_MSB_ADDR) 438 | sw = ((sw_msb << 8) | sw_lsb) & 0xFFFF 439 | # Return the results as a tuple of all 5 values. 440 | return (sw, bl, accel, mag, gyro) 441 | 442 | def set_external_crystal(self, external_crystal): 443 | """Set if an external crystal is being used by passing True, otherwise 444 | use the internal oscillator by passing False (the default behavior). 445 | """ 446 | # Switch to configuration mode. 447 | self._config_mode() 448 | # Set the clock bit appropriately in the SYS_TRIGGER register. 449 | if external_crystal: 450 | self._write_byte(BNO055_SYS_TRIGGER_ADDR, 0x80) 451 | else: 452 | self._write_byte(BNO055_SYS_TRIGGER_ADDR, 0x00) 453 | # Go back to normal operation mode. 454 | self._operation_mode() 455 | 456 | def get_system_status(self, run_self_test=True): 457 | """Return a tuple with status information. Three values will be returned: 458 | - System status register value with the following meaning: 459 | 0 = Idle 460 | 1 = System Error 461 | 2 = Initializing Peripherals 462 | 3 = System Initialization 463 | 4 = Executing Self-Test 464 | 5 = Sensor fusion algorithm running 465 | 6 = System running without fusion algorithms 466 | - Self test result register value with the following meaning: 467 | Bit value: 1 = test passed, 0 = test failed 468 | Bit 0 = Accelerometer self test 469 | Bit 1 = Magnetometer self test 470 | Bit 2 = Gyroscope self test 471 | Bit 3 = MCU self test 472 | Value of 0x0F = all good! 473 | - System error register value with the following meaning: 474 | 0 = No error 475 | 1 = Peripheral initialization error 476 | 2 = System initialization error 477 | 3 = Self test result failed 478 | 4 = Register map value out of range 479 | 5 = Register map address out of range 480 | 6 = Register map write error 481 | 7 = BNO low power mode not available for selected operation mode 482 | 8 = Accelerometer power mode not available 483 | 9 = Fusion algorithm configuration error 484 | 10 = Sensor configuration error 485 | 486 | If run_self_test is passed in as False then no self test is performed and 487 | None will be returned for the self test result. Note that running a 488 | self test requires going into config mode which will stop the fusion 489 | engine from running. 490 | """ 491 | self_test = None 492 | if run_self_test: 493 | # Switch to configuration mode if running self test. 494 | self._config_mode() 495 | # Perform a self test. 496 | sys_trigger = self._read_byte(BNO055_SYS_TRIGGER_ADDR) 497 | self._write_byte(BNO055_SYS_TRIGGER_ADDR, sys_trigger | 0x1) 498 | # Wait for self test to finish. 499 | time.sleep(1.0) 500 | # Read test result. 501 | self_test = self._read_byte(BNO055_SELFTEST_RESULT_ADDR) 502 | # Go back to operation mode. 503 | self._operation_mode() 504 | # Now read status and error registers. 505 | status = self._read_byte(BNO055_SYS_STAT_ADDR) 506 | error = self._read_byte(BNO055_SYS_ERR_ADDR) 507 | # Return the results as a tuple of all 3 values. 508 | return (status, self_test, error) 509 | 510 | def get_calibration_status(self): 511 | """Read the calibration status of the sensors and return a 4 tuple with 512 | calibration status as follows: 513 | - System, 3=fully calibrated, 0=not calibrated 514 | - Gyroscope, 3=fully calibrated, 0=not calibrated 515 | - Accelerometer, 3=fully calibrated, 0=not calibrated 516 | - Magnetometer, 3=fully calibrated, 0=not calibrated 517 | """ 518 | # Return the calibration status register value. 519 | cal_status = self._read_byte(BNO055_CALIB_STAT_ADDR) 520 | sys = (cal_status >> 6) & 0x03 521 | gyro = (cal_status >> 4) & 0x03 522 | accel = (cal_status >> 2) & 0x03 523 | mag = cal_status & 0x03 524 | # Return the results as a tuple of all 3 values. 525 | return (sys, gyro, accel, mag) 526 | 527 | def get_calibration(self): 528 | """Return the sensor's calibration data and return it as an array of 529 | 22 bytes. Can be saved and then reloaded with the set_calibration function 530 | to quickly calibrate from a previously calculated set of calibration data. 531 | """ 532 | # Switch to configuration mode, as mentioned in section 3.10.4 of datasheet. 533 | self._config_mode() 534 | # Read the 22 bytes of calibration data and convert it to a list (from 535 | # a bytearray) so it's more easily serialized should the caller want to 536 | # store it. 537 | cal_data = list(self._read_bytes(ACCEL_OFFSET_X_LSB_ADDR, 22)) 538 | # Go back to normal operation mode. 539 | self._operation_mode() 540 | return cal_data 541 | 542 | def set_calibration(self, data): 543 | """Set the sensor's calibration data using a list of 22 bytes that 544 | represent the sensor offsets and calibration data. This data should be 545 | a value that was previously retrieved with get_calibration (and then 546 | perhaps persisted to disk or other location until needed again). 547 | """ 548 | # Check that 22 bytes were passed in with calibration data. 549 | if data is None or len(data) != 22: 550 | raise ValueError('Expected a list of 22 bytes for calibration data.') 551 | # Switch to configuration mode, as mentioned in section 3.10.4 of datasheet. 552 | self._config_mode() 553 | # Set the 22 bytes of calibration data. 554 | self._write_bytes(ACCEL_OFFSET_X_LSB_ADDR, data) 555 | # Go back to normal operation mode. 556 | self._operation_mode() 557 | 558 | def get_axis_remap(self): 559 | """Return a tuple with the axis remap register values. This will return 560 | 6 values with the following meaning: 561 | - X axis remap (a value of AXIS_REMAP_X, AXIS_REMAP_Y, or AXIS_REMAP_Z. 562 | which indicates that the physical X axis of the chip 563 | is remapped to a different axis) 564 | - Y axis remap (see above) 565 | - Z axis remap (see above) 566 | - X axis sign (a value of AXIS_REMAP_POSITIVE or AXIS_REMAP_NEGATIVE 567 | which indicates if the X axis values should be positive/ 568 | normal or negative/inverted. The default is positive.) 569 | - Y axis sign (see above) 570 | - Z axis sign (see above) 571 | 572 | Note that by default the axis orientation of the BNO chip looks like 573 | the following (taken from section 3.4, page 24 of the datasheet). Notice 574 | the dot in the corner that corresponds to the dot on the BNO chip: 575 | 576 | | Z axis 577 | | 578 | | / X axis 579 | ____|__/____ 580 | Y axis / * | / /| 581 | _________ /______|/ // 582 | /___________ // 583 | |____________|/ 584 | """ 585 | # Get the axis remap register value. 586 | map_config = self._read_byte(BNO055_AXIS_MAP_CONFIG_ADDR) 587 | z = (map_config >> 4) & 0x03 588 | y = (map_config >> 2) & 0x03 589 | x = map_config & 0x03 590 | # Get the axis remap sign register value. 591 | sign_config = self._read_byte(BNO055_AXIS_MAP_SIGN_ADDR) 592 | x_sign = (sign_config >> 2) & 0x01 593 | y_sign = (sign_config >> 1) & 0x01 594 | z_sign = sign_config & 0x01 595 | # Return the results as a tuple of all 3 values. 596 | return (x, y, z, x_sign, y_sign, z_sign) 597 | 598 | def set_axis_remap(self, x, y, z, 599 | x_sign=AXIS_REMAP_POSITIVE, y_sign=AXIS_REMAP_POSITIVE, 600 | z_sign=AXIS_REMAP_POSITIVE): 601 | """Set axis remap for each axis. The x, y, z parameter values should 602 | be set to one of AXIS_REMAP_X, AXIS_REMAP_Y, or AXIS_REMAP_Z and will 603 | change the BNO's axis to represent another axis. Note that two axises 604 | cannot be mapped to the same axis, so the x, y, z params should be a 605 | unique combination of AXIS_REMAP_X, AXIS_REMAP_Y, AXIS_REMAP_Z values. 606 | 607 | The x_sign, y_sign, z_sign values represent if the axis should be positive 608 | or negative (inverted). 609 | 610 | See the get_axis_remap documentation for information on the orientation 611 | of the axises on the chip, and consult section 3.4 of the datasheet. 612 | """ 613 | # Switch to configuration mode. 614 | self._config_mode() 615 | # Set the axis remap register value. 616 | map_config = 0x00 617 | map_config |= (z & 0x03) << 4 618 | map_config |= (y & 0x03) << 2 619 | map_config |= x & 0x03 620 | self._write_byte(BNO055_AXIS_MAP_CONFIG_ADDR, map_config) 621 | # Set the axis remap sign register value. 622 | sign_config = 0x00 623 | sign_config |= (x_sign & 0x01) << 2 624 | sign_config |= (y_sign & 0x01) << 1 625 | sign_config |= z_sign & 0x01 626 | self._write_byte(BNO055_AXIS_MAP_SIGN_ADDR, sign_config) 627 | # Go back to normal operation mode. 628 | self._operation_mode() 629 | 630 | def _read_vector(self, address, count=3): 631 | # Read count number of 16-bit signed values starting from the provided 632 | # address. Returns a tuple of the values that were read. 633 | data = self._read_bytes(address, count*2) 634 | result = [0]*count 635 | for i in range(count): 636 | result[i] = ((data[i*2+1] << 8) | data[i*2]) & 0xFFFF 637 | if result[i] > 32767: 638 | result[i] -= 65536 639 | return result 640 | 641 | def read_euler(self): 642 | """Return the current absolute orientation as a tuple of heading, roll, 643 | and pitch euler angles in degrees. 644 | """ 645 | heading, roll, pitch = self._read_vector(BNO055_EULER_H_LSB_ADDR) 646 | return (heading/16.0, roll/16.0, pitch/16.0) 647 | 648 | def read_magnetometer(self): 649 | """Return the current magnetometer reading as a tuple of X, Y, Z values 650 | in micro-Teslas. 651 | """ 652 | x, y, z = self._read_vector(BNO055_MAG_DATA_X_LSB_ADDR) 653 | return (x/16.0, y/16.0, z/16.0) 654 | 655 | def read_gyroscope(self): 656 | """Return the current gyroscope (angular velocity) reading as a tuple of 657 | X, Y, Z values in degrees per second. 658 | """ 659 | x, y, z = self._read_vector(BNO055_GYRO_DATA_X_LSB_ADDR) 660 | return (x/900.0, y/900.0, z/900.0) 661 | 662 | def read_accelerometer(self): 663 | """Return the current accelerometer reading as a tuple of X, Y, Z values 664 | in meters/second^2. 665 | """ 666 | x, y, z = self._read_vector(BNO055_ACCEL_DATA_X_LSB_ADDR) 667 | return (x/100.0, y/100.0, z/100.0) 668 | 669 | def read_linear_acceleration(self): 670 | """Return the current linear acceleration (acceleration from movement, 671 | not from gravity) reading as a tuple of X, Y, Z values in meters/second^2. 672 | """ 673 | x, y, z = self._read_vector(BNO055_LINEAR_ACCEL_DATA_X_LSB_ADDR) 674 | return (x/100.0, y/100.0, z/100.0) 675 | 676 | def read_gravity(self): 677 | """Return the current gravity acceleration reading as a tuple of X, Y, Z 678 | values in meters/second^2. 679 | """ 680 | x, y, z = self._read_vector(BNO055_GRAVITY_DATA_X_LSB_ADDR) 681 | return (x/100.0, y/100.0, z/100.0) 682 | 683 | def read_quaternion(self): 684 | """Return the current orientation as a tuple of X, Y, Z, W quaternion 685 | values. 686 | """ 687 | w, x, y, z = self._read_vector(BNO055_QUATERNION_DATA_W_LSB_ADDR, 4) 688 | # Scale values, see 3.6.5.5 in the datasheet. 689 | scale = (1.0 / (1<<14)) 690 | return (x*scale, y*scale, z*scale, w*scale) 691 | 692 | def read_temp(self): 693 | """Return the current temperature in Celsius.""" 694 | return self._read_signed_byte(BNO055_TEMP_ADDR) 695 | -------------------------------------------------------------------------------- /Adafruit_BNO055/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_Python_BNO055/ce9d7ae76cb23b8962d2dddc48f943bd8416831d/Adafruit_BNO055/__init__.py -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Adafruit Industries 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | Twitter Bootstrap is copyright 2011-2015 Twitter, Inc. and released 24 | under a MIT license. See more details at its homepage: 25 | http://getbootstrap.com/ 26 | 27 | Three.js library is copyright 2015-2016 three.js authors and released 28 | under a MIT license. See more details at its homepage: 29 | http://threejs.org/ 30 | 31 | jQuery is copyright jQuery Foundation and other contributors and released 32 | under a license at: 33 | https://github.com/jquery/jquery/blob/master/LICENSE.txt 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **DEPRECATED** 2 | Please use new version of library: 3 | https://github.com/adafruit/Adafruit_CircuitPython_BNO055 4 | 5 | # Adafruit Python BNO055 6 | 7 | Library for accessing the Bosch BNO055 absolute orientation sensor on a Raspberry Pi or Beaglebone Black. 8 | -------------------------------------------------------------------------------- /examples/simpletest.py: -------------------------------------------------------------------------------- 1 | # Simple Adafruit BNO055 sensor reading example. Will print the orientation 2 | # and calibration data every second. 3 | # 4 | # Copyright (c) 2015 Adafruit Industries 5 | # Author: Tony DiCola 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | # THE SOFTWARE. 24 | import logging 25 | import sys 26 | import time 27 | 28 | from Adafruit_BNO055 import BNO055 29 | 30 | 31 | # Create and configure the BNO sensor connection. Make sure only ONE of the 32 | # below 'bno = ...' lines is uncommented: 33 | # Raspberry Pi configuration with serial UART and RST connected to GPIO 18: 34 | bno = BNO055.BNO055(serial_port='/dev/serial0', rst=18) 35 | # BeagleBone Black configuration with default I2C connection (SCL=P9_19, SDA=P9_20), 36 | # and RST connected to pin P9_12: 37 | #bno = BNO055.BNO055(rst='P9_12') 38 | 39 | 40 | # Enable verbose debug logging if -v is passed as a parameter. 41 | if len(sys.argv) == 2 and sys.argv[1].lower() == '-v': 42 | logging.basicConfig(level=logging.DEBUG) 43 | 44 | # Initialize the BNO055 and stop if something went wrong. 45 | if not bno.begin(): 46 | raise RuntimeError('Failed to initialize BNO055! Is the sensor connected?') 47 | 48 | # Print system status and self test result. 49 | status, self_test, error = bno.get_system_status() 50 | print('System status: {0}'.format(status)) 51 | print('Self test result (0x0F is normal): 0x{0:02X}'.format(self_test)) 52 | # Print out an error if system status is in error mode. 53 | if status == 0x01: 54 | print('System error: {0}'.format(error)) 55 | print('See datasheet section 4.3.59 for the meaning.') 56 | 57 | # Print BNO055 software revision and other diagnostic data. 58 | sw, bl, accel, mag, gyro = bno.get_revision() 59 | print('Software version: {0}'.format(sw)) 60 | print('Bootloader version: {0}'.format(bl)) 61 | print('Accelerometer ID: 0x{0:02X}'.format(accel)) 62 | print('Magnetometer ID: 0x{0:02X}'.format(mag)) 63 | print('Gyroscope ID: 0x{0:02X}\n'.format(gyro)) 64 | 65 | print('Reading BNO055 data, press Ctrl-C to quit...') 66 | while True: 67 | # Read the Euler angles for heading, roll, pitch (all in degrees). 68 | heading, roll, pitch = bno.read_euler() 69 | # Read the calibration status, 0=uncalibrated and 3=fully calibrated. 70 | sys, gyro, accel, mag = bno.get_calibration_status() 71 | # Print everything out. 72 | print('Heading={0:0.2F} Roll={1:0.2F} Pitch={2:0.2F}\tSys_cal={3} Gyro_cal={4} Accel_cal={5} Mag_cal={6}'.format( 73 | heading, roll, pitch, sys, gyro, accel, mag)) 74 | # Other values you can optionally read: 75 | # Orientation as a quaternion: 76 | #x,y,z,w = bno.read_quaterion() 77 | # Sensor temperature in degrees Celsius: 78 | #temp_c = bno.read_temp() 79 | # Magnetometer data (in micro-Teslas): 80 | #x,y,z = bno.read_magnetometer() 81 | # Gyroscope data (in degrees per second): 82 | #x,y,z = bno.read_gyroscope() 83 | # Accelerometer data (in meters per second squared): 84 | #x,y,z = bno.read_accelerometer() 85 | # Linear acceleration data (i.e. acceleration from movement, not gravity-- 86 | # returned in meters per second squared): 87 | #x,y,z = bno.read_linear_acceleration() 88 | # Gravity acceleration data (i.e. acceleration just from gravity--returned 89 | # in meters per second squared): 90 | #x,y,z = bno.read_gravity() 91 | # Sleep for a second until the next reading. 92 | time.sleep(1) 93 | -------------------------------------------------------------------------------- /examples/webgl_demo/server.py: -------------------------------------------------------------------------------- 1 | # Adafruit BNO055 WebGL Example 2 | # 3 | # Requires the flask web framework to be installed. See http://flask.pocoo.org/ 4 | # for installation instructions, however on a Linux machine like the Raspberry 5 | # Pi or BeagleBone black you can likely install it by running: 6 | # sudo apt-get update 7 | # sudo apt-get install python-pip 8 | # sudo pip install flask 9 | # 10 | # Copyright (c) 2015 Adafruit Industries 11 | # Author: Tony DiCola 12 | # 13 | # Permission is hereby granted, free of charge, to any person obtaining a copy 14 | # of this software and associated documentation files (the "Software"), to deal 15 | # in the Software without restriction, including without limitation the rights 16 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | # copies of the Software, and to permit persons to whom the Software is 18 | # furnished to do so, subject to the following conditions: 19 | # 20 | # The above copyright notice and this permission notice shall be included in 21 | # all copies or substantial portions of the Software. 22 | # 23 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | # THE SOFTWARE. 30 | import json 31 | import logging 32 | import threading 33 | import time 34 | 35 | from flask import * 36 | 37 | from Adafruit_BNO055 import BNO055 38 | 39 | 40 | # Create and configure the BNO sensor connection. Make sure only ONE of the 41 | # below 'bno = ...' lines is uncommented: 42 | # Raspberry Pi configuration with serial UART and RST connected to GPIO 18: 43 | bno = BNO055.BNO055(serial_port='/dev/serial0', rst=18) 44 | # BeagleBone Black configuration with default I2C connection (SCL=P9_19, SDA=P9_20), 45 | # and RST connected to pin P9_12: 46 | #bno = BNO055.BNO055(rst='P9_12') 47 | 48 | # Application configuration below. You probably don't need to change these values. 49 | 50 | # How often to update the BNO sensor data (in hertz). 51 | BNO_UPDATE_FREQUENCY_HZ = 10 52 | 53 | # Name of the file to store calibration data when the save/load calibration 54 | # button is pressed. Calibration data is stored in JSON format. 55 | CALIBRATION_FILE = 'calibration.json' 56 | 57 | # BNO sensor axes remap values. These are the parameters to the BNO.set_axis_remap 58 | # function. Don't change these without consulting section 3.4 of the datasheet. 59 | # The default axes mapping below assumes the Adafruit BNO055 breakout is flat on 60 | # a table with the row of SDA, SCL, GND, VIN, etc pins facing away from you. 61 | BNO_AXIS_REMAP = { 'x': BNO055.AXIS_REMAP_X, 62 | 'y': BNO055.AXIS_REMAP_Z, 63 | 'z': BNO055.AXIS_REMAP_Y, 64 | 'x_sign': BNO055.AXIS_REMAP_POSITIVE, 65 | 'y_sign': BNO055.AXIS_REMAP_POSITIVE, 66 | 'z_sign': BNO055.AXIS_REMAP_NEGATIVE } 67 | 68 | 69 | # Create flask application. 70 | app = Flask(__name__) 71 | 72 | # Global state to keep track of the latest readings from the BNO055 sensor. 73 | # This will be accessed from multiple threads so care needs to be taken to 74 | # protect access with a lock (or else inconsistent/partial results might be read). 75 | # A condition object is used both as a lock for safe access across threads, and 76 | # to notify threads that the BNO state has changed. 77 | bno_data = {} 78 | bno_changed = threading.Condition() 79 | 80 | # Background thread to read BNO sensor data. Will be created right before 81 | # the first request is served (see start_bno_thread below). 82 | bno_thread = None 83 | 84 | 85 | def read_bno(): 86 | """Function to read the BNO sensor and update the bno_data object with the 87 | latest BNO orientation, etc. state. Must be run in its own thread because 88 | it will never return! 89 | """ 90 | while True: 91 | # Grab new BNO sensor readings. 92 | temp = bno.read_temp() 93 | heading, roll, pitch = bno.read_euler() 94 | x, y, z, w = bno.read_quaternion() 95 | sys, gyro, accel, mag = bno.get_calibration_status() 96 | status, self_test, error = bno.get_system_status(run_self_test=False) 97 | if error != 0: 98 | print 'Error! Value: {0}'.format(error) 99 | # Capture the lock on the bno_changed condition so the bno_data shared 100 | # state can be updated. 101 | with bno_changed: 102 | bno_data['euler'] = (heading, roll, pitch) 103 | bno_data['temp'] = temp 104 | bno_data['quaternion'] = (x, y, z, w) 105 | bno_data['calibration'] = (sys, gyro, accel, mag) 106 | # Notify any waiting threads that the BNO state has been updated. 107 | bno_changed.notifyAll() 108 | # Sleep until the next reading. 109 | time.sleep(1.0/BNO_UPDATE_FREQUENCY_HZ) 110 | 111 | def bno_sse(): 112 | """Function to handle sending BNO055 sensor data to the client web browser 113 | using HTML5 server sent events (aka server push). This is a generator function 114 | that flask will run in a thread and call to get new data that is pushed to 115 | the client web page. 116 | """ 117 | # Loop forever waiting for a new BNO055 sensor reading and sending it to 118 | # the client. Since this is a generator function the yield statement is 119 | # used to return a new result. 120 | while True: 121 | # Capture the bno_changed condition lock and then wait for it to notify 122 | # a new reading is available. 123 | with bno_changed: 124 | bno_changed.wait() 125 | # A new reading is available! Grab the reading value and then give 126 | # up the lock. 127 | heading, roll, pitch = bno_data['euler'] 128 | temp = bno_data['temp'] 129 | x, y, z, w = bno_data['quaternion'] 130 | sys, gyro, accel, mag = bno_data['calibration'] 131 | # Send the data to the connected client in HTML5 server sent event format. 132 | data = {'heading': heading, 'roll': roll, 'pitch': pitch, 'temp': temp, 133 | 'quatX': x, 'quatY': y, 'quatZ': z, 'quatW': w, 134 | 'calSys': sys, 'calGyro': gyro, 'calAccel': accel, 'calMag': mag } 135 | yield 'data: {0}\n\n'.format(json.dumps(data)) 136 | 137 | 138 | @app.before_first_request 139 | def start_bno_thread(): 140 | # Start the BNO thread right before the first request is served. This is 141 | # necessary because in debug mode flask will start multiple main threads so 142 | # this is the only spot to put code that can only run once after starting. 143 | # See this SO question for more context: 144 | # http://stackoverflow.com/questions/24617795/starting-thread-while-running-flask-with-debug 145 | global bno_thread 146 | # Initialize BNO055 sensor. 147 | if not bno.begin(): 148 | raise RuntimeError('Failed to initialize BNO055!') 149 | bno.set_axis_remap(**BNO_AXIS_REMAP) 150 | # Kick off BNO055 reading thread. 151 | bno_thread = threading.Thread(target=read_bno) 152 | bno_thread.daemon = True # Don't let the BNO reading thread block exiting. 153 | bno_thread.start() 154 | 155 | @app.route('/bno') 156 | def bno_path(): 157 | # Return SSE response and call bno_sse function to stream sensor data to 158 | # the webpage. 159 | return Response(bno_sse(), mimetype='text/event-stream') 160 | 161 | @app.route('/save_calibration', methods=['POST']) 162 | def save_calibration(): 163 | # Save calibration data to disk. 164 | # First grab the lock on BNO sensor access to make sure nothing else is 165 | # writing to the sensor right now. 166 | with bno_changed: 167 | data = bno.get_calibration() 168 | # Write the calibration to disk. 169 | with open(CALIBRATION_FILE, 'w') as cal_file: 170 | json.dump(data, cal_file) 171 | return 'OK' 172 | 173 | @app.route('/load_calibration', methods=['POST']) 174 | def load_calibration(): 175 | # Load calibration from disk. 176 | with open(CALIBRATION_FILE, 'r') as cal_file: 177 | data = json.load(cal_file) 178 | # Grab the lock on BNO sensor access to serial access to the sensor. 179 | with bno_changed: 180 | bno.set_calibration(data) 181 | return 'OK' 182 | 183 | @app.route('/') 184 | def root(): 185 | return render_template('index.html') 186 | 187 | 188 | if __name__ == '__main__': 189 | # Create a server listening for external connections on the default 190 | # port 5000. Enable debug mode for better error messages and live 191 | # reloading of the server on changes. Also make the server threaded 192 | # so multiple connections can be processed at once (very important 193 | # for using server sent events). 194 | app.run(host='0.0.0.0', debug=True, threaded=True) 195 | -------------------------------------------------------------------------------- /examples/webgl_demo/static/bunny.mtl: -------------------------------------------------------------------------------- 1 | # 3ds Max Wavefront OBJ Exporter v0.94b - (c)2007 guruware 2 | # File Created: 04.07.2010 10:41:39 3 | 4 | newmtl Body 5 | Ns 32 6 | d 1 7 | Tr 1 8 | Tf 1 1 1 9 | illum 2 10 | Ka 0.0000 0.0000 0.0000 11 | Kd 0.7412 0.4784 0.4765 12 | Ks 0.3500 0.3500 0.6500 13 | 14 | -------------------------------------------------------------------------------- /examples/webgl_demo/static/cat-top.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_Python_BNO055/ce9d7ae76cb23b8962d2dddc48f943bd8416831d/examples/webgl_demo/static/cat-top.stl -------------------------------------------------------------------------------- /examples/webgl_demo/static/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.5 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | .btn-default, 7 | .btn-primary, 8 | .btn-success, 9 | .btn-info, 10 | .btn-warning, 11 | .btn-danger { 12 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 13 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 14 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | } 16 | .btn-default:active, 17 | .btn-primary:active, 18 | .btn-success:active, 19 | .btn-info:active, 20 | .btn-warning:active, 21 | .btn-danger:active, 22 | .btn-default.active, 23 | .btn-primary.active, 24 | .btn-success.active, 25 | .btn-info.active, 26 | .btn-warning.active, 27 | .btn-danger.active { 28 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 29 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | } 31 | .btn-default.disabled, 32 | .btn-primary.disabled, 33 | .btn-success.disabled, 34 | .btn-info.disabled, 35 | .btn-warning.disabled, 36 | .btn-danger.disabled, 37 | .btn-default[disabled], 38 | .btn-primary[disabled], 39 | .btn-success[disabled], 40 | .btn-info[disabled], 41 | .btn-warning[disabled], 42 | .btn-danger[disabled], 43 | fieldset[disabled] .btn-default, 44 | fieldset[disabled] .btn-primary, 45 | fieldset[disabled] .btn-success, 46 | fieldset[disabled] .btn-info, 47 | fieldset[disabled] .btn-warning, 48 | fieldset[disabled] .btn-danger { 49 | -webkit-box-shadow: none; 50 | box-shadow: none; 51 | } 52 | .btn-default .badge, 53 | .btn-primary .badge, 54 | .btn-success .badge, 55 | .btn-info .badge, 56 | .btn-warning .badge, 57 | .btn-danger .badge { 58 | text-shadow: none; 59 | } 60 | .btn:active, 61 | .btn.active { 62 | background-image: none; 63 | } 64 | .btn-default { 65 | text-shadow: 0 1px 0 #fff; 66 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 67 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 68 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 69 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 70 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 71 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 72 | background-repeat: repeat-x; 73 | border-color: #dbdbdb; 74 | border-color: #ccc; 75 | } 76 | .btn-default:hover, 77 | .btn-default:focus { 78 | background-color: #e0e0e0; 79 | background-position: 0 -15px; 80 | } 81 | .btn-default:active, 82 | .btn-default.active { 83 | background-color: #e0e0e0; 84 | border-color: #dbdbdb; 85 | } 86 | .btn-default.disabled, 87 | .btn-default[disabled], 88 | fieldset[disabled] .btn-default, 89 | .btn-default.disabled:hover, 90 | .btn-default[disabled]:hover, 91 | fieldset[disabled] .btn-default:hover, 92 | .btn-default.disabled:focus, 93 | .btn-default[disabled]:focus, 94 | fieldset[disabled] .btn-default:focus, 95 | .btn-default.disabled.focus, 96 | .btn-default[disabled].focus, 97 | fieldset[disabled] .btn-default.focus, 98 | .btn-default.disabled:active, 99 | .btn-default[disabled]:active, 100 | fieldset[disabled] .btn-default:active, 101 | .btn-default.disabled.active, 102 | .btn-default[disabled].active, 103 | fieldset[disabled] .btn-default.active { 104 | background-color: #e0e0e0; 105 | background-image: none; 106 | } 107 | .btn-primary { 108 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); 109 | background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); 110 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); 111 | background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); 112 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); 113 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 114 | background-repeat: repeat-x; 115 | border-color: #245580; 116 | } 117 | .btn-primary:hover, 118 | .btn-primary:focus { 119 | background-color: #265a88; 120 | background-position: 0 -15px; 121 | } 122 | .btn-primary:active, 123 | .btn-primary.active { 124 | background-color: #265a88; 125 | border-color: #245580; 126 | } 127 | .btn-primary.disabled, 128 | .btn-primary[disabled], 129 | fieldset[disabled] .btn-primary, 130 | .btn-primary.disabled:hover, 131 | .btn-primary[disabled]:hover, 132 | fieldset[disabled] .btn-primary:hover, 133 | .btn-primary.disabled:focus, 134 | .btn-primary[disabled]:focus, 135 | fieldset[disabled] .btn-primary:focus, 136 | .btn-primary.disabled.focus, 137 | .btn-primary[disabled].focus, 138 | fieldset[disabled] .btn-primary.focus, 139 | .btn-primary.disabled:active, 140 | .btn-primary[disabled]:active, 141 | fieldset[disabled] .btn-primary:active, 142 | .btn-primary.disabled.active, 143 | .btn-primary[disabled].active, 144 | fieldset[disabled] .btn-primary.active { 145 | background-color: #265a88; 146 | background-image: none; 147 | } 148 | .btn-success { 149 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 150 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 151 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 152 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 153 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 154 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 155 | background-repeat: repeat-x; 156 | border-color: #3e8f3e; 157 | } 158 | .btn-success:hover, 159 | .btn-success:focus { 160 | background-color: #419641; 161 | background-position: 0 -15px; 162 | } 163 | .btn-success:active, 164 | .btn-success.active { 165 | background-color: #419641; 166 | border-color: #3e8f3e; 167 | } 168 | .btn-success.disabled, 169 | .btn-success[disabled], 170 | fieldset[disabled] .btn-success, 171 | .btn-success.disabled:hover, 172 | .btn-success[disabled]:hover, 173 | fieldset[disabled] .btn-success:hover, 174 | .btn-success.disabled:focus, 175 | .btn-success[disabled]:focus, 176 | fieldset[disabled] .btn-success:focus, 177 | .btn-success.disabled.focus, 178 | .btn-success[disabled].focus, 179 | fieldset[disabled] .btn-success.focus, 180 | .btn-success.disabled:active, 181 | .btn-success[disabled]:active, 182 | fieldset[disabled] .btn-success:active, 183 | .btn-success.disabled.active, 184 | .btn-success[disabled].active, 185 | fieldset[disabled] .btn-success.active { 186 | background-color: #419641; 187 | background-image: none; 188 | } 189 | .btn-info { 190 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 191 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 192 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 193 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 194 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 195 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 196 | background-repeat: repeat-x; 197 | border-color: #28a4c9; 198 | } 199 | .btn-info:hover, 200 | .btn-info:focus { 201 | background-color: #2aabd2; 202 | background-position: 0 -15px; 203 | } 204 | .btn-info:active, 205 | .btn-info.active { 206 | background-color: #2aabd2; 207 | border-color: #28a4c9; 208 | } 209 | .btn-info.disabled, 210 | .btn-info[disabled], 211 | fieldset[disabled] .btn-info, 212 | .btn-info.disabled:hover, 213 | .btn-info[disabled]:hover, 214 | fieldset[disabled] .btn-info:hover, 215 | .btn-info.disabled:focus, 216 | .btn-info[disabled]:focus, 217 | fieldset[disabled] .btn-info:focus, 218 | .btn-info.disabled.focus, 219 | .btn-info[disabled].focus, 220 | fieldset[disabled] .btn-info.focus, 221 | .btn-info.disabled:active, 222 | .btn-info[disabled]:active, 223 | fieldset[disabled] .btn-info:active, 224 | .btn-info.disabled.active, 225 | .btn-info[disabled].active, 226 | fieldset[disabled] .btn-info.active { 227 | background-color: #2aabd2; 228 | background-image: none; 229 | } 230 | .btn-warning { 231 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 232 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 233 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 234 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 235 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 236 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 237 | background-repeat: repeat-x; 238 | border-color: #e38d13; 239 | } 240 | .btn-warning:hover, 241 | .btn-warning:focus { 242 | background-color: #eb9316; 243 | background-position: 0 -15px; 244 | } 245 | .btn-warning:active, 246 | .btn-warning.active { 247 | background-color: #eb9316; 248 | border-color: #e38d13; 249 | } 250 | .btn-warning.disabled, 251 | .btn-warning[disabled], 252 | fieldset[disabled] .btn-warning, 253 | .btn-warning.disabled:hover, 254 | .btn-warning[disabled]:hover, 255 | fieldset[disabled] .btn-warning:hover, 256 | .btn-warning.disabled:focus, 257 | .btn-warning[disabled]:focus, 258 | fieldset[disabled] .btn-warning:focus, 259 | .btn-warning.disabled.focus, 260 | .btn-warning[disabled].focus, 261 | fieldset[disabled] .btn-warning.focus, 262 | .btn-warning.disabled:active, 263 | .btn-warning[disabled]:active, 264 | fieldset[disabled] .btn-warning:active, 265 | .btn-warning.disabled.active, 266 | .btn-warning[disabled].active, 267 | fieldset[disabled] .btn-warning.active { 268 | background-color: #eb9316; 269 | background-image: none; 270 | } 271 | .btn-danger { 272 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 273 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 274 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 275 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 276 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 277 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 278 | background-repeat: repeat-x; 279 | border-color: #b92c28; 280 | } 281 | .btn-danger:hover, 282 | .btn-danger:focus { 283 | background-color: #c12e2a; 284 | background-position: 0 -15px; 285 | } 286 | .btn-danger:active, 287 | .btn-danger.active { 288 | background-color: #c12e2a; 289 | border-color: #b92c28; 290 | } 291 | .btn-danger.disabled, 292 | .btn-danger[disabled], 293 | fieldset[disabled] .btn-danger, 294 | .btn-danger.disabled:hover, 295 | .btn-danger[disabled]:hover, 296 | fieldset[disabled] .btn-danger:hover, 297 | .btn-danger.disabled:focus, 298 | .btn-danger[disabled]:focus, 299 | fieldset[disabled] .btn-danger:focus, 300 | .btn-danger.disabled.focus, 301 | .btn-danger[disabled].focus, 302 | fieldset[disabled] .btn-danger.focus, 303 | .btn-danger.disabled:active, 304 | .btn-danger[disabled]:active, 305 | fieldset[disabled] .btn-danger:active, 306 | .btn-danger.disabled.active, 307 | .btn-danger[disabled].active, 308 | fieldset[disabled] .btn-danger.active { 309 | background-color: #c12e2a; 310 | background-image: none; 311 | } 312 | .thumbnail, 313 | .img-thumbnail { 314 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 315 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 316 | } 317 | .dropdown-menu > li > a:hover, 318 | .dropdown-menu > li > a:focus { 319 | background-color: #e8e8e8; 320 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 321 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 322 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 323 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 324 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 325 | background-repeat: repeat-x; 326 | } 327 | .dropdown-menu > .active > a, 328 | .dropdown-menu > .active > a:hover, 329 | .dropdown-menu > .active > a:focus { 330 | background-color: #2e6da4; 331 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 332 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 333 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 334 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 335 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 336 | background-repeat: repeat-x; 337 | } 338 | .navbar-default { 339 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 340 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 341 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 342 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 343 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 344 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 345 | background-repeat: repeat-x; 346 | border-radius: 4px; 347 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 348 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 349 | } 350 | .navbar-default .navbar-nav > .open > a, 351 | .navbar-default .navbar-nav > .active > a { 352 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 353 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 354 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); 355 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); 356 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); 357 | background-repeat: repeat-x; 358 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 359 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 360 | } 361 | .navbar-brand, 362 | .navbar-nav > li > a { 363 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 364 | } 365 | .navbar-inverse { 366 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 367 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 368 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 369 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 370 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 371 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 372 | background-repeat: repeat-x; 373 | border-radius: 4px; 374 | } 375 | .navbar-inverse .navbar-nav > .open > a, 376 | .navbar-inverse .navbar-nav > .active > a { 377 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); 378 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); 379 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); 380 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); 381 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); 382 | background-repeat: repeat-x; 383 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 384 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 385 | } 386 | .navbar-inverse .navbar-brand, 387 | .navbar-inverse .navbar-nav > li > a { 388 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 389 | } 390 | .navbar-static-top, 391 | .navbar-fixed-top, 392 | .navbar-fixed-bottom { 393 | border-radius: 0; 394 | } 395 | @media (max-width: 767px) { 396 | .navbar .navbar-nav .open .dropdown-menu > .active > a, 397 | .navbar .navbar-nav .open .dropdown-menu > .active > a:hover, 398 | .navbar .navbar-nav .open .dropdown-menu > .active > a:focus { 399 | color: #fff; 400 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 401 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 403 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 405 | background-repeat: repeat-x; 406 | } 407 | } 408 | .alert { 409 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 410 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 411 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 412 | } 413 | .alert-success { 414 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 415 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 416 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 417 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 418 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 419 | background-repeat: repeat-x; 420 | border-color: #b2dba1; 421 | } 422 | .alert-info { 423 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 424 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 425 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 426 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 427 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 428 | background-repeat: repeat-x; 429 | border-color: #9acfea; 430 | } 431 | .alert-warning { 432 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 433 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 434 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 435 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 436 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 437 | background-repeat: repeat-x; 438 | border-color: #f5e79e; 439 | } 440 | .alert-danger { 441 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 442 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 443 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 444 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 445 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 446 | background-repeat: repeat-x; 447 | border-color: #dca7a7; 448 | } 449 | .progress { 450 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 451 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 452 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 453 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 454 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 455 | background-repeat: repeat-x; 456 | } 457 | .progress-bar { 458 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); 459 | background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); 460 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); 461 | background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); 462 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); 463 | background-repeat: repeat-x; 464 | } 465 | .progress-bar-success { 466 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 467 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 468 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 469 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 470 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 471 | background-repeat: repeat-x; 472 | } 473 | .progress-bar-info { 474 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 475 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 476 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 477 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 478 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 479 | background-repeat: repeat-x; 480 | } 481 | .progress-bar-warning { 482 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 483 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 484 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 485 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 486 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 487 | background-repeat: repeat-x; 488 | } 489 | .progress-bar-danger { 490 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 491 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 492 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 493 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 494 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 495 | background-repeat: repeat-x; 496 | } 497 | .progress-bar-striped { 498 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 499 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 500 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 501 | } 502 | .list-group { 503 | border-radius: 4px; 504 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 505 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 506 | } 507 | .list-group-item.active, 508 | .list-group-item.active:hover, 509 | .list-group-item.active:focus { 510 | text-shadow: 0 -1px 0 #286090; 511 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); 512 | background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); 513 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); 514 | background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); 515 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); 516 | background-repeat: repeat-x; 517 | border-color: #2b669a; 518 | } 519 | .list-group-item.active .badge, 520 | .list-group-item.active:hover .badge, 521 | .list-group-item.active:focus .badge { 522 | text-shadow: none; 523 | } 524 | .panel { 525 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 526 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 527 | } 528 | .panel-default > .panel-heading { 529 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 530 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 531 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 532 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 533 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 534 | background-repeat: repeat-x; 535 | } 536 | .panel-primary > .panel-heading { 537 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 538 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 539 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 540 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 541 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 542 | background-repeat: repeat-x; 543 | } 544 | .panel-success > .panel-heading { 545 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 546 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 547 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 548 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 549 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 550 | background-repeat: repeat-x; 551 | } 552 | .panel-info > .panel-heading { 553 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 554 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 555 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 556 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 557 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 558 | background-repeat: repeat-x; 559 | } 560 | .panel-warning > .panel-heading { 561 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 562 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 563 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 564 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 565 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 566 | background-repeat: repeat-x; 567 | } 568 | .panel-danger > .panel-heading { 569 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 570 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 571 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 572 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 573 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 574 | background-repeat: repeat-x; 575 | } 576 | .well { 577 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 578 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 579 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 580 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 581 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 582 | background-repeat: repeat-x; 583 | border-color: #dcdcdc; 584 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 585 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 586 | } 587 | /*# sourceMappingURL=bootstrap-theme.css.map */ 588 | -------------------------------------------------------------------------------- /examples/webgl_demo/static/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.5 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /examples/webgl_demo/static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_Python_BNO055/ce9d7ae76cb23b8962d2dddc48f943bd8416831d/examples/webgl_demo/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /examples/webgl_demo/static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_Python_BNO055/ce9d7ae76cb23b8962d2dddc48f943bd8416831d/examples/webgl_demo/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /examples/webgl_demo/static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_Python_BNO055/ce9d7ae76cb23b8962d2dddc48f943bd8416831d/examples/webgl_demo/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /examples/webgl_demo/static/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_Python_BNO055/ce9d7ae76cb23b8962d2dddc48f943bd8416831d/examples/webgl_demo/static/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /examples/webgl_demo/static/js/DDSLoader.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | THREE.DDSLoader = function () { 6 | this._parser = THREE.DDSLoader.parse; 7 | }; 8 | 9 | THREE.DDSLoader.prototype = Object.create( THREE.CompressedTextureLoader.prototype ); 10 | THREE.DDSLoader.prototype.constructor = THREE.DDSLoader; 11 | 12 | THREE.DDSLoader.parse = function ( buffer, loadMipmaps ) { 13 | 14 | var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 }; 15 | 16 | // Adapted from @toji's DDS utils 17 | // https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js 18 | 19 | // All values and structures referenced from: 20 | // http://msdn.microsoft.com/en-us/library/bb943991.aspx/ 21 | 22 | var DDS_MAGIC = 0x20534444; 23 | 24 | var DDSD_CAPS = 0x1, 25 | DDSD_HEIGHT = 0x2, 26 | DDSD_WIDTH = 0x4, 27 | DDSD_PITCH = 0x8, 28 | DDSD_PIXELFORMAT = 0x1000, 29 | DDSD_MIPMAPCOUNT = 0x20000, 30 | DDSD_LINEARSIZE = 0x80000, 31 | DDSD_DEPTH = 0x800000; 32 | 33 | var DDSCAPS_COMPLEX = 0x8, 34 | DDSCAPS_MIPMAP = 0x400000, 35 | DDSCAPS_TEXTURE = 0x1000; 36 | 37 | var DDSCAPS2_CUBEMAP = 0x200, 38 | DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, 39 | DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, 40 | DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, 41 | DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, 42 | DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, 43 | DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, 44 | DDSCAPS2_VOLUME = 0x200000; 45 | 46 | var DDPF_ALPHAPIXELS = 0x1, 47 | DDPF_ALPHA = 0x2, 48 | DDPF_FOURCC = 0x4, 49 | DDPF_RGB = 0x40, 50 | DDPF_YUV = 0x200, 51 | DDPF_LUMINANCE = 0x20000; 52 | 53 | function fourCCToInt32( value ) { 54 | 55 | return value.charCodeAt(0) + 56 | (value.charCodeAt(1) << 8) + 57 | (value.charCodeAt(2) << 16) + 58 | (value.charCodeAt(3) << 24); 59 | 60 | } 61 | 62 | function int32ToFourCC( value ) { 63 | 64 | return String.fromCharCode( 65 | value & 0xff, 66 | (value >> 8) & 0xff, 67 | (value >> 16) & 0xff, 68 | (value >> 24) & 0xff 69 | ); 70 | } 71 | 72 | function loadARGBMip( buffer, dataOffset, width, height ) { 73 | var dataLength = width * height * 4; 74 | var srcBuffer = new Uint8Array( buffer, dataOffset, dataLength ); 75 | var byteArray = new Uint8Array( dataLength ); 76 | var dst = 0; 77 | var src = 0; 78 | for ( var y = 0; y < height; y ++ ) { 79 | for ( var x = 0; x < width; x ++ ) { 80 | var b = srcBuffer[src]; src ++; 81 | var g = srcBuffer[src]; src ++; 82 | var r = srcBuffer[src]; src ++; 83 | var a = srcBuffer[src]; src ++; 84 | byteArray[dst] = r; dst ++; //r 85 | byteArray[dst] = g; dst ++; //g 86 | byteArray[dst] = b; dst ++; //b 87 | byteArray[dst] = a; dst ++; //a 88 | } 89 | } 90 | return byteArray; 91 | } 92 | 93 | var FOURCC_DXT1 = fourCCToInt32("DXT1"); 94 | var FOURCC_DXT3 = fourCCToInt32("DXT3"); 95 | var FOURCC_DXT5 = fourCCToInt32("DXT5"); 96 | 97 | var headerLengthInt = 31; // The header length in 32 bit ints 98 | 99 | // Offsets into the header array 100 | 101 | var off_magic = 0; 102 | 103 | var off_size = 1; 104 | var off_flags = 2; 105 | var off_height = 3; 106 | var off_width = 4; 107 | 108 | var off_mipmapCount = 7; 109 | 110 | var off_pfFlags = 20; 111 | var off_pfFourCC = 21; 112 | var off_RGBBitCount = 22; 113 | var off_RBitMask = 23; 114 | var off_GBitMask = 24; 115 | var off_BBitMask = 25; 116 | var off_ABitMask = 26; 117 | 118 | var off_caps = 27; 119 | var off_caps2 = 28; 120 | var off_caps3 = 29; 121 | var off_caps4 = 30; 122 | 123 | // Parse header 124 | 125 | var header = new Int32Array( buffer, 0, headerLengthInt ); 126 | 127 | if ( header[ off_magic ] !== DDS_MAGIC ) { 128 | 129 | console.error( 'THREE.DDSLoader.parse: Invalid magic number in DDS header.' ); 130 | return dds; 131 | 132 | } 133 | 134 | if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) { 135 | 136 | console.error( 'THREE.DDSLoader.parse: Unsupported format, must contain a FourCC code.' ); 137 | return dds; 138 | 139 | } 140 | 141 | var blockBytes; 142 | 143 | var fourCC = header[ off_pfFourCC ]; 144 | 145 | var isRGBAUncompressed = false; 146 | 147 | switch ( fourCC ) { 148 | 149 | case FOURCC_DXT1: 150 | 151 | blockBytes = 8; 152 | dds.format = THREE.RGB_S3TC_DXT1_Format; 153 | break; 154 | 155 | case FOURCC_DXT3: 156 | 157 | blockBytes = 16; 158 | dds.format = THREE.RGBA_S3TC_DXT3_Format; 159 | break; 160 | 161 | case FOURCC_DXT5: 162 | 163 | blockBytes = 16; 164 | dds.format = THREE.RGBA_S3TC_DXT5_Format; 165 | break; 166 | 167 | default: 168 | 169 | if ( header[off_RGBBitCount] == 32 170 | && header[off_RBitMask]&0xff0000 171 | && header[off_GBitMask]&0xff00 172 | && header[off_BBitMask]&0xff 173 | && header[off_ABitMask]&0xff000000 ) { 174 | isRGBAUncompressed = true; 175 | blockBytes = 64; 176 | dds.format = THREE.RGBAFormat; 177 | } else { 178 | console.error( 'THREE.DDSLoader.parse: Unsupported FourCC code ', int32ToFourCC( fourCC ) ); 179 | return dds; 180 | } 181 | } 182 | 183 | dds.mipmapCount = 1; 184 | 185 | if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) { 186 | 187 | dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] ); 188 | 189 | } 190 | 191 | //TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc. 192 | 193 | dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false; 194 | 195 | dds.width = header[ off_width ]; 196 | dds.height = header[ off_height ]; 197 | 198 | var dataOffset = header[ off_size ] + 4; 199 | 200 | // Extract mipmaps buffers 201 | 202 | var width = dds.width; 203 | var height = dds.height; 204 | 205 | var faces = dds.isCubemap ? 6 : 1; 206 | 207 | for ( var face = 0; face < faces; face ++ ) { 208 | 209 | for ( var i = 0; i < dds.mipmapCount; i ++ ) { 210 | 211 | if ( isRGBAUncompressed ) { 212 | var byteArray = loadARGBMip( buffer, dataOffset, width, height ); 213 | var dataLength = byteArray.length; 214 | } else { 215 | var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes; 216 | var byteArray = new Uint8Array( buffer, dataOffset, dataLength ); 217 | } 218 | 219 | var mipmap = { "data": byteArray, "width": width, "height": height }; 220 | dds.mipmaps.push( mipmap ); 221 | 222 | dataOffset += dataLength; 223 | 224 | width = Math.max( width * 0.5, 1 ); 225 | height = Math.max( height * 0.5, 1 ); 226 | 227 | } 228 | 229 | width = dds.width; 230 | height = dds.height; 231 | 232 | } 233 | 234 | return dds; 235 | 236 | }; 237 | 238 | -------------------------------------------------------------------------------- /examples/webgl_demo/static/js/MTLLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Loads a Wavefront .mtl file specifying materials 3 | * 4 | * @author angelxuanchang 5 | */ 6 | 7 | THREE.MTLLoader = function( baseUrl, options, crossOrigin ) { 8 | 9 | this.baseUrl = baseUrl; 10 | this.options = options; 11 | this.crossOrigin = crossOrigin; 12 | 13 | }; 14 | 15 | THREE.MTLLoader.prototype = { 16 | 17 | constructor: THREE.MTLLoader, 18 | 19 | load: function ( url, onLoad, onProgress, onError ) { 20 | 21 | var scope = this; 22 | 23 | var loader = new THREE.XHRLoader(); 24 | loader.setCrossOrigin( this.crossOrigin ); 25 | loader.load( url, function ( text ) { 26 | 27 | onLoad( scope.parse( text ) ); 28 | 29 | }, onProgress, onError ); 30 | 31 | }, 32 | 33 | /** 34 | * Parses loaded MTL file 35 | * @param text - Content of MTL file 36 | * @return {THREE.MTLLoader.MaterialCreator} 37 | */ 38 | parse: function ( text ) { 39 | 40 | var lines = text.split( "\n" ); 41 | var info = {}; 42 | var delimiter_pattern = /\s+/; 43 | var materialsInfo = {}; 44 | 45 | for ( var i = 0; i < lines.length; i ++ ) { 46 | 47 | var line = lines[ i ]; 48 | line = line.trim(); 49 | 50 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) { 51 | 52 | // Blank line or comment ignore 53 | continue; 54 | 55 | } 56 | 57 | var pos = line.indexOf( ' ' ); 58 | 59 | var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line; 60 | key = key.toLowerCase(); 61 | 62 | var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : ""; 63 | value = value.trim(); 64 | 65 | if ( key === "newmtl" ) { 66 | 67 | // New material 68 | 69 | info = { name: value }; 70 | materialsInfo[ value ] = info; 71 | 72 | } else if ( info ) { 73 | 74 | if ( key === "ka" || key === "kd" || key === "ks" ) { 75 | 76 | var ss = value.split( delimiter_pattern, 3 ); 77 | info[ key ] = [ parseFloat( ss[0] ), parseFloat( ss[1] ), parseFloat( ss[2] ) ]; 78 | 79 | } else { 80 | 81 | info[ key ] = value; 82 | 83 | } 84 | 85 | } 86 | 87 | } 88 | 89 | var materialCreator = new THREE.MTLLoader.MaterialCreator( this.baseUrl, this.options ); 90 | materialCreator.crossOrigin = this.crossOrigin 91 | materialCreator.setMaterials( materialsInfo ); 92 | return materialCreator; 93 | 94 | } 95 | 96 | }; 97 | 98 | /** 99 | * Create a new THREE-MTLLoader.MaterialCreator 100 | * @param baseUrl - Url relative to which textures are loaded 101 | * @param options - Set of options on how to construct the materials 102 | * side: Which side to apply the material 103 | * THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide 104 | * wrap: What type of wrapping to apply for textures 105 | * THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping 106 | * normalizeRGB: RGBs need to be normalized to 0-1 from 0-255 107 | * Default: false, assumed to be already normalized 108 | * ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's 109 | * Default: false 110 | * invertTransparency: If transparency need to be inverted (inversion is needed if d = 0 is fully opaque) 111 | * Default: false (d = 1 is fully opaque) 112 | * @constructor 113 | */ 114 | 115 | THREE.MTLLoader.MaterialCreator = function( baseUrl, options ) { 116 | 117 | this.baseUrl = baseUrl; 118 | this.options = options; 119 | this.materialsInfo = {}; 120 | this.materials = {}; 121 | this.materialsArray = []; 122 | this.nameLookup = {}; 123 | 124 | this.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide; 125 | this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping; 126 | 127 | }; 128 | 129 | THREE.MTLLoader.MaterialCreator.prototype = { 130 | 131 | constructor: THREE.MTLLoader.MaterialCreator, 132 | 133 | setMaterials: function( materialsInfo ) { 134 | 135 | this.materialsInfo = this.convert( materialsInfo ); 136 | this.materials = {}; 137 | this.materialsArray = []; 138 | this.nameLookup = {}; 139 | 140 | }, 141 | 142 | convert: function( materialsInfo ) { 143 | 144 | if ( !this.options ) return materialsInfo; 145 | 146 | var converted = {}; 147 | 148 | for ( var mn in materialsInfo ) { 149 | 150 | // Convert materials info into normalized form based on options 151 | 152 | var mat = materialsInfo[ mn ]; 153 | 154 | var covmat = {}; 155 | 156 | converted[ mn ] = covmat; 157 | 158 | for ( var prop in mat ) { 159 | 160 | var save = true; 161 | var value = mat[ prop ]; 162 | var lprop = prop.toLowerCase(); 163 | 164 | switch ( lprop ) { 165 | 166 | case 'kd': 167 | case 'ka': 168 | case 'ks': 169 | 170 | // Diffuse color (color under white light) using RGB values 171 | 172 | if ( this.options && this.options.normalizeRGB ) { 173 | 174 | value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ]; 175 | 176 | } 177 | 178 | if ( this.options && this.options.ignoreZeroRGBs ) { 179 | 180 | if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 1 ] === 0 ) { 181 | 182 | // ignore 183 | 184 | save = false; 185 | 186 | } 187 | } 188 | 189 | break; 190 | 191 | case 'd': 192 | 193 | // According to MTL format (http://paulbourke.net/dataformats/mtl/): 194 | // d is dissolve for current material 195 | // factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent) 196 | 197 | if ( this.options && this.options.invertTransparency ) { 198 | 199 | value = 1 - value; 200 | 201 | } 202 | 203 | break; 204 | 205 | default: 206 | 207 | break; 208 | } 209 | 210 | if ( save ) { 211 | 212 | covmat[ lprop ] = value; 213 | 214 | } 215 | 216 | } 217 | 218 | } 219 | 220 | return converted; 221 | 222 | }, 223 | 224 | preload: function () { 225 | 226 | for ( var mn in this.materialsInfo ) { 227 | 228 | this.create( mn ); 229 | 230 | } 231 | 232 | }, 233 | 234 | getIndex: function( materialName ) { 235 | 236 | return this.nameLookup[ materialName ]; 237 | 238 | }, 239 | 240 | getAsArray: function() { 241 | 242 | var index = 0; 243 | 244 | for ( var mn in this.materialsInfo ) { 245 | 246 | this.materialsArray[ index ] = this.create( mn ); 247 | this.nameLookup[ mn ] = index; 248 | index ++; 249 | 250 | } 251 | 252 | return this.materialsArray; 253 | 254 | }, 255 | 256 | create: function ( materialName ) { 257 | 258 | if ( this.materials[ materialName ] === undefined ) { 259 | 260 | this.createMaterial_( materialName ); 261 | 262 | } 263 | 264 | return this.materials[ materialName ]; 265 | 266 | }, 267 | 268 | createMaterial_: function ( materialName ) { 269 | 270 | // Create material 271 | 272 | var mat = this.materialsInfo[ materialName ]; 273 | var params = { 274 | 275 | name: materialName, 276 | side: this.side 277 | 278 | }; 279 | 280 | for ( var prop in mat ) { 281 | 282 | var value = mat[ prop ]; 283 | 284 | switch ( prop.toLowerCase() ) { 285 | 286 | // Ns is material specular exponent 287 | 288 | case 'kd': 289 | 290 | // Diffuse color (color under white light) using RGB values 291 | 292 | params[ 'diffuse' ] = new THREE.Color().fromArray( value ); 293 | 294 | break; 295 | 296 | case 'ka': 297 | 298 | // Ambient color (color under shadow) using RGB values 299 | 300 | break; 301 | 302 | case 'ks': 303 | 304 | // Specular color (color when light is reflected from shiny surface) using RGB values 305 | params[ 'specular' ] = new THREE.Color().fromArray( value ); 306 | 307 | break; 308 | 309 | case 'map_kd': 310 | 311 | // Diffuse texture map 312 | 313 | params[ 'map' ] = this.loadTexture( this.baseUrl + value ); 314 | params[ 'map' ].wrapS = this.wrap; 315 | params[ 'map' ].wrapT = this.wrap; 316 | 317 | break; 318 | 319 | case 'ns': 320 | 321 | // The specular exponent (defines the focus of the specular highlight) 322 | // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000. 323 | 324 | params['shininess'] = value; 325 | 326 | break; 327 | 328 | case 'd': 329 | 330 | // According to MTL format (http://paulbourke.net/dataformats/mtl/): 331 | // d is dissolve for current material 332 | // factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent) 333 | 334 | if ( value < 1 ) { 335 | 336 | params['transparent'] = true; 337 | params['opacity'] = value; 338 | 339 | } 340 | 341 | break; 342 | 343 | case 'map_bump': 344 | case 'bump': 345 | 346 | // Bump texture map 347 | 348 | if ( params[ 'bumpMap' ] ) break; // Avoid loading twice. 349 | 350 | params[ 'bumpMap' ] = this.loadTexture( this.baseUrl + value ); 351 | params[ 'bumpMap' ].wrapS = this.wrap; 352 | params[ 'bumpMap' ].wrapT = this.wrap; 353 | 354 | break; 355 | 356 | default: 357 | break; 358 | 359 | } 360 | 361 | } 362 | 363 | if ( params[ 'diffuse' ] ) { 364 | 365 | params[ 'color' ] = params[ 'diffuse' ]; 366 | 367 | } 368 | 369 | this.materials[ materialName ] = new THREE.MeshPhongMaterial( params ); 370 | return this.materials[ materialName ]; 371 | 372 | }, 373 | 374 | 375 | loadTexture: function ( url, mapping, onLoad, onError ) { 376 | 377 | var texture; 378 | var loader = THREE.Loader.Handlers.get( url ); 379 | 380 | if ( loader !== null ) { 381 | 382 | texture = loader.load( url, onLoad ); 383 | 384 | } else { 385 | 386 | texture = new THREE.Texture(); 387 | 388 | loader = new THREE.ImageLoader(); 389 | loader.crossOrigin = this.crossOrigin; 390 | loader.load( url, function ( image ) { 391 | 392 | texture.image = THREE.MTLLoader.ensurePowerOfTwo_( image ); 393 | texture.needsUpdate = true; 394 | 395 | if ( onLoad ) onLoad( texture ); 396 | 397 | } ); 398 | 399 | } 400 | 401 | if ( mapping !== undefined ) texture.mapping = mapping; 402 | 403 | return texture; 404 | 405 | } 406 | 407 | }; 408 | 409 | THREE.MTLLoader.ensurePowerOfTwo_ = function ( image ) { 410 | 411 | if ( ! THREE.Math.isPowerOfTwo( image.width ) || ! THREE.Math.isPowerOfTwo( image.height ) ) { 412 | 413 | var canvas = document.createElement( "canvas" ); 414 | canvas.width = THREE.MTLLoader.nextHighestPowerOfTwo_( image.width ); 415 | canvas.height = THREE.MTLLoader.nextHighestPowerOfTwo_( image.height ); 416 | 417 | var ctx = canvas.getContext("2d"); 418 | ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); 419 | return canvas; 420 | 421 | } 422 | 423 | return image; 424 | 425 | }; 426 | 427 | THREE.MTLLoader.nextHighestPowerOfTwo_ = function( x ) { 428 | 429 | -- x; 430 | 431 | for ( var i = 1; i < 32; i <<= 1 ) { 432 | 433 | x = x | x >> i; 434 | 435 | } 436 | 437 | return x + 1; 438 | 439 | }; 440 | 441 | THREE.EventDispatcher.prototype.apply( THREE.MTLLoader.prototype ); 442 | -------------------------------------------------------------------------------- /examples/webgl_demo/static/js/OBJLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | THREE.OBJLoader = function ( manager ) { 6 | 7 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 8 | 9 | }; 10 | 11 | THREE.OBJLoader.prototype = { 12 | 13 | constructor: THREE.OBJLoader, 14 | 15 | load: function ( url, onLoad, onProgress, onError ) { 16 | 17 | var scope = this; 18 | 19 | var loader = new THREE.XHRLoader( scope.manager ); 20 | loader.setCrossOrigin( this.crossOrigin ); 21 | loader.load( url, function ( text ) { 22 | 23 | onLoad( scope.parse( text ) ); 24 | 25 | }, onProgress, onError ); 26 | 27 | }, 28 | 29 | parse: function ( text ) { 30 | 31 | console.time( 'OBJLoader' ); 32 | 33 | var object, objects = []; 34 | var geometry, material; 35 | 36 | function parseVertexIndex( value ) { 37 | 38 | var index = parseInt( value ); 39 | 40 | return ( index >= 0 ? index - 1 : index + vertices.length / 3 ) * 3; 41 | 42 | } 43 | 44 | function parseNormalIndex( value ) { 45 | 46 | var index = parseInt( value ); 47 | 48 | return ( index >= 0 ? index - 1 : index + normals.length / 3 ) * 3; 49 | 50 | } 51 | 52 | function parseUVIndex( value ) { 53 | 54 | var index = parseInt( value ); 55 | 56 | return ( index >= 0 ? index - 1 : index + uvs.length / 2 ) * 2; 57 | 58 | } 59 | 60 | function addVertex( a, b, c ) { 61 | 62 | geometry.vertices.push( 63 | vertices[ a ], vertices[ a + 1 ], vertices[ a + 2 ], 64 | vertices[ b ], vertices[ b + 1 ], vertices[ b + 2 ], 65 | vertices[ c ], vertices[ c + 1 ], vertices[ c + 2 ] 66 | ); 67 | 68 | } 69 | 70 | function addNormal( a, b, c ) { 71 | 72 | geometry.normals.push( 73 | normals[ a ], normals[ a + 1 ], normals[ a + 2 ], 74 | normals[ b ], normals[ b + 1 ], normals[ b + 2 ], 75 | normals[ c ], normals[ c + 1 ], normals[ c + 2 ] 76 | ); 77 | 78 | } 79 | 80 | function addUV( a, b, c ) { 81 | 82 | geometry.uvs.push( 83 | uvs[ a ], uvs[ a + 1 ], 84 | uvs[ b ], uvs[ b + 1 ], 85 | uvs[ c ], uvs[ c + 1 ] 86 | ); 87 | 88 | } 89 | 90 | function addFace( a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd ) { 91 | 92 | var ia = parseVertexIndex( a ); 93 | var ib = parseVertexIndex( b ); 94 | var ic = parseVertexIndex( c ); 95 | var id; 96 | 97 | if ( d === undefined ) { 98 | 99 | addVertex( ia, ib, ic ); 100 | 101 | } else { 102 | 103 | id = parseVertexIndex( d ); 104 | 105 | addVertex( ia, ib, id ); 106 | addVertex( ib, ic, id ); 107 | 108 | } 109 | 110 | if ( ua !== undefined ) { 111 | 112 | ia = parseUVIndex( ua ); 113 | ib = parseUVIndex( ub ); 114 | ic = parseUVIndex( uc ); 115 | 116 | if ( d === undefined ) { 117 | 118 | addUV( ia, ib, ic ); 119 | 120 | } else { 121 | 122 | id = parseUVIndex( ud ); 123 | 124 | addUV( ia, ib, id ); 125 | addUV( ib, ic, id ); 126 | 127 | } 128 | 129 | } 130 | 131 | if ( na !== undefined ) { 132 | 133 | ia = parseNormalIndex( na ); 134 | ib = parseNormalIndex( nb ); 135 | ic = parseNormalIndex( nc ); 136 | 137 | if ( d === undefined ) { 138 | 139 | addNormal( ia, ib, ic ); 140 | 141 | } else { 142 | 143 | id = parseNormalIndex( nd ); 144 | 145 | addNormal( ia, ib, id ); 146 | addNormal( ib, ic, id ); 147 | 148 | } 149 | 150 | } 151 | 152 | } 153 | 154 | // create mesh if no objects in text 155 | 156 | if ( /^o /gm.test( text ) === false ) { 157 | 158 | geometry = { 159 | vertices: [], 160 | normals: [], 161 | uvs: [] 162 | }; 163 | 164 | material = { 165 | name: '' 166 | }; 167 | 168 | object = { 169 | name: '', 170 | geometry: geometry, 171 | material: material 172 | }; 173 | 174 | objects.push( object ); 175 | 176 | } 177 | 178 | var vertices = []; 179 | var normals = []; 180 | var uvs = []; 181 | 182 | // v float float float 183 | 184 | var vertex_pattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; 185 | 186 | // vn float float float 187 | 188 | var normal_pattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; 189 | 190 | // vt float float 191 | 192 | var uv_pattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; 193 | 194 | // f vertex vertex vertex ... 195 | 196 | var face_pattern1 = /f( +-?\d+)( +-?\d+)( +-?\d+)( +-?\d+)?/; 197 | 198 | // f vertex/uv vertex/uv vertex/uv ... 199 | 200 | var face_pattern2 = /f( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))?/; 201 | 202 | // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... 203 | 204 | var face_pattern3 = /f( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))?/; 205 | 206 | // f vertex//normal vertex//normal vertex//normal ... 207 | 208 | var face_pattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/ 209 | 210 | // 211 | 212 | var lines = text.split( '\n' ); 213 | 214 | for ( var i = 0; i < lines.length; i ++ ) { 215 | 216 | var line = lines[ i ]; 217 | line = line.trim(); 218 | 219 | var result; 220 | 221 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) { 222 | 223 | continue; 224 | 225 | } else if ( ( result = vertex_pattern.exec( line ) ) !== null ) { 226 | 227 | // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 228 | 229 | vertices.push( 230 | parseFloat( result[ 1 ] ), 231 | parseFloat( result[ 2 ] ), 232 | parseFloat( result[ 3 ] ) 233 | ); 234 | 235 | } else if ( ( result = normal_pattern.exec( line ) ) !== null ) { 236 | 237 | // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 238 | 239 | normals.push( 240 | parseFloat( result[ 1 ] ), 241 | parseFloat( result[ 2 ] ), 242 | parseFloat( result[ 3 ] ) 243 | ); 244 | 245 | } else if ( ( result = uv_pattern.exec( line ) ) !== null ) { 246 | 247 | // ["vt 0.1 0.2", "0.1", "0.2"] 248 | 249 | uvs.push( 250 | parseFloat( result[ 1 ] ), 251 | parseFloat( result[ 2 ] ) 252 | ); 253 | 254 | } else if ( ( result = face_pattern1.exec( line ) ) !== null ) { 255 | 256 | // ["f 1 2 3", "1", "2", "3", undefined] 257 | 258 | addFace( 259 | result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ] 260 | ); 261 | 262 | } else if ( ( result = face_pattern2.exec( line ) ) !== null ) { 263 | 264 | // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined] 265 | 266 | addFace( 267 | result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ], 268 | result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] 269 | ); 270 | 271 | } else if ( ( result = face_pattern3.exec( line ) ) !== null ) { 272 | 273 | // ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined] 274 | 275 | addFace( 276 | result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ], 277 | result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ], 278 | result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ] 279 | ); 280 | 281 | } else if ( ( result = face_pattern4.exec( line ) ) !== null ) { 282 | 283 | // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined] 284 | 285 | addFace( 286 | result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ], 287 | undefined, undefined, undefined, undefined, 288 | result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] 289 | ); 290 | 291 | } else if ( /^o /.test( line ) ) { 292 | 293 | geometry = { 294 | vertices: [], 295 | normals: [], 296 | uvs: [] 297 | }; 298 | 299 | material = { 300 | name: '' 301 | }; 302 | 303 | object = { 304 | name: line.substring( 2 ).trim(), 305 | geometry: geometry, 306 | material: material 307 | }; 308 | 309 | objects.push( object ) 310 | 311 | } else if ( /^g /.test( line ) ) { 312 | 313 | // group 314 | 315 | } else if ( /^usemtl /.test( line ) ) { 316 | 317 | // material 318 | 319 | material.name = line.substring( 7 ).trim(); 320 | 321 | } else if ( /^mtllib /.test( line ) ) { 322 | 323 | // mtl file 324 | 325 | } else if ( /^s /.test( line ) ) { 326 | 327 | // smooth shading 328 | 329 | } else { 330 | 331 | // console.log( "THREE.OBJLoader: Unhandled line " + line ); 332 | 333 | } 334 | 335 | } 336 | 337 | var container = new THREE.Object3D(); 338 | 339 | for ( var i = 0, l = objects.length; i < l; i ++ ) { 340 | 341 | object = objects[ i ]; 342 | geometry = object.geometry; 343 | 344 | var buffergeometry = new THREE.BufferGeometry(); 345 | 346 | buffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) ); 347 | 348 | if ( geometry.normals.length > 0 ) { 349 | buffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) ); 350 | } 351 | 352 | if ( geometry.uvs.length > 0 ) { 353 | buffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) ); 354 | } 355 | 356 | material = new THREE.MeshLambertMaterial(); 357 | material.name = object.material.name; 358 | 359 | var mesh = new THREE.Mesh( buffergeometry, material ); 360 | mesh.name = object.name; 361 | 362 | container.add( mesh ); 363 | 364 | } 365 | 366 | console.timeEnd( 'OBJLoader' ); 367 | 368 | return container; 369 | 370 | } 371 | 372 | }; 373 | -------------------------------------------------------------------------------- /examples/webgl_demo/static/js/OBJMTLLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Loads a Wavefront .obj file with materials 3 | * 4 | * @author mrdoob / http://mrdoob.com/ 5 | * @author angelxuanchang 6 | */ 7 | 8 | THREE.OBJMTLLoader = function ( manager ) { 9 | 10 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 11 | 12 | }; 13 | 14 | THREE.OBJMTLLoader.prototype = { 15 | 16 | constructor: THREE.OBJMTLLoader, 17 | 18 | load: function ( url, mtlurl, onLoad, onProgress, onError ) { 19 | 20 | var scope = this; 21 | 22 | var mtlLoader = new THREE.MTLLoader( url.substr( 0, url.lastIndexOf( "/" ) + 1 ) ); 23 | mtlLoader.crossOrigin = scope.crossOrigin; 24 | mtlLoader.load( mtlurl, function ( materials ) { 25 | 26 | var materialsCreator = materials; 27 | materialsCreator.preload(); 28 | 29 | var loader = new THREE.XHRLoader( scope.manager ); 30 | loader.setCrossOrigin( scope.crossOrigin ); 31 | loader.load( url, function ( text ) { 32 | 33 | var object = scope.parse( text ); 34 | 35 | object.traverse( function ( object ) { 36 | 37 | if ( object instanceof THREE.Mesh ) { 38 | 39 | if ( object.material.name ) { 40 | 41 | var material = materialsCreator.create( object.material.name ); 42 | 43 | if ( material ) object.material = material; 44 | 45 | } 46 | 47 | } 48 | 49 | } ); 50 | 51 | onLoad( object ); 52 | 53 | }, onProgress, onError ); 54 | 55 | }, onProgress, onError ); 56 | 57 | }, 58 | 59 | /** 60 | * Parses loaded .obj file 61 | * @param data - content of .obj file 62 | * @param mtllibCallback - callback to handle mtllib declaration (optional) 63 | * @return {THREE.Object3D} - Object3D (with default material) 64 | */ 65 | 66 | parse: function ( data, mtllibCallback ) { 67 | 68 | function vector( x, y, z ) { 69 | 70 | return new THREE.Vector3( x, y, z ); 71 | 72 | } 73 | 74 | function uv( u, v ) { 75 | 76 | return new THREE.Vector2( u, v ); 77 | 78 | } 79 | 80 | function face3( a, b, c, normals ) { 81 | 82 | return new THREE.Face3( a, b, c, normals ); 83 | 84 | } 85 | 86 | var face_offset = 0; 87 | 88 | function meshN( meshName, materialName ) { 89 | 90 | if ( vertices.length > 0 ) { 91 | 92 | geometry.vertices = vertices; 93 | 94 | geometry.mergeVertices(); 95 | geometry.computeFaceNormals(); 96 | geometry.computeBoundingSphere(); 97 | 98 | object.add( mesh ); 99 | 100 | geometry = new THREE.Geometry(); 101 | mesh = new THREE.Mesh( geometry, material ); 102 | 103 | } 104 | 105 | if ( meshName !== undefined ) mesh.name = meshName; 106 | 107 | if ( materialName !== undefined ) { 108 | 109 | material = new THREE.MeshLambertMaterial(); 110 | material.name = materialName; 111 | 112 | mesh.material = material; 113 | 114 | } 115 | 116 | } 117 | 118 | var group = new THREE.Group(); 119 | var object = group; 120 | 121 | var geometry = new THREE.Geometry(); 122 | var material = new THREE.MeshLambertMaterial(); 123 | var mesh = new THREE.Mesh( geometry, material ); 124 | 125 | var vertices = []; 126 | var normals = []; 127 | var uvs = []; 128 | 129 | function add_face( a, b, c, normals_inds ) { 130 | 131 | if ( normals_inds === undefined ) { 132 | 133 | geometry.faces.push( face3( 134 | parseInt( a ) - (face_offset + 1), 135 | parseInt( b ) - (face_offset + 1), 136 | parseInt( c ) - (face_offset + 1) 137 | ) ); 138 | 139 | } else { 140 | 141 | geometry.faces.push( face3( 142 | parseInt( a ) - (face_offset + 1), 143 | parseInt( b ) - (face_offset + 1), 144 | parseInt( c ) - (face_offset + 1), 145 | [ 146 | normals[ parseInt( normals_inds[ 0 ] ) - 1 ].clone(), 147 | normals[ parseInt( normals_inds[ 1 ] ) - 1 ].clone(), 148 | normals[ parseInt( normals_inds[ 2 ] ) - 1 ].clone() 149 | ] 150 | ) ); 151 | 152 | } 153 | 154 | } 155 | 156 | function add_uvs( a, b, c ) { 157 | 158 | geometry.faceVertexUvs[ 0 ].push( [ 159 | uvs[ parseInt( a ) - 1 ].clone(), 160 | uvs[ parseInt( b ) - 1 ].clone(), 161 | uvs[ parseInt( c ) - 1 ].clone() 162 | ] ); 163 | 164 | } 165 | 166 | function handle_face_line(faces, uvs, normals_inds) { 167 | 168 | if ( faces[ 3 ] === undefined ) { 169 | 170 | add_face( faces[ 0 ], faces[ 1 ], faces[ 2 ], normals_inds ); 171 | 172 | if (!(uvs === undefined) && uvs.length > 0) { 173 | add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 2 ] ); 174 | } 175 | 176 | } else { 177 | 178 | if (!(normals_inds === undefined) && normals_inds.length > 0) { 179 | 180 | add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ], [ normals_inds[ 0 ], normals_inds[ 1 ], normals_inds[ 3 ] ]); 181 | add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ], [ normals_inds[ 1 ], normals_inds[ 2 ], normals_inds[ 3 ] ]); 182 | 183 | } else { 184 | 185 | add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ]); 186 | add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ]); 187 | 188 | } 189 | 190 | if (!(uvs === undefined) && uvs.length > 0) { 191 | 192 | add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ); 193 | add_uvs( uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ); 194 | 195 | } 196 | 197 | } 198 | 199 | } 200 | 201 | 202 | // v float float float 203 | 204 | var vertex_pattern = /v( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; 205 | 206 | // vn float float float 207 | 208 | var normal_pattern = /vn( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; 209 | 210 | // vt float float 211 | 212 | var uv_pattern = /vt( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; 213 | 214 | // f vertex vertex vertex ... 215 | 216 | var face_pattern1 = /f( +\d+)( +\d+)( +\d+)( +\d+)?/; 217 | 218 | // f vertex/uv vertex/uv vertex/uv ... 219 | 220 | var face_pattern2 = /f( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))?/; 221 | 222 | // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... 223 | 224 | var face_pattern3 = /f( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))?/; 225 | 226 | // f vertex//normal vertex//normal vertex//normal ... 227 | 228 | var face_pattern4 = /f( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))?/ 229 | 230 | // 231 | 232 | var lines = data.split( "\n" ); 233 | 234 | for ( var i = 0; i < lines.length; i ++ ) { 235 | 236 | var line = lines[ i ]; 237 | line = line.trim(); 238 | 239 | var result; 240 | 241 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) { 242 | 243 | continue; 244 | 245 | } else if ( ( result = vertex_pattern.exec( line ) ) !== null ) { 246 | 247 | // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 248 | 249 | vertices.push( vector( 250 | parseFloat( result[ 1 ] ), 251 | parseFloat( result[ 2 ] ), 252 | parseFloat( result[ 3 ] ) 253 | ) ); 254 | 255 | } else if ( ( result = normal_pattern.exec( line ) ) !== null ) { 256 | 257 | // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 258 | 259 | normals.push( vector( 260 | parseFloat( result[ 1 ] ), 261 | parseFloat( result[ 2 ] ), 262 | parseFloat( result[ 3 ] ) 263 | ) ); 264 | 265 | } else if ( ( result = uv_pattern.exec( line ) ) !== null ) { 266 | 267 | // ["vt 0.1 0.2", "0.1", "0.2"] 268 | 269 | uvs.push( uv( 270 | parseFloat( result[ 1 ] ), 271 | parseFloat( result[ 2 ] ) 272 | ) ); 273 | 274 | } else if ( ( result = face_pattern1.exec( line ) ) !== null ) { 275 | 276 | // ["f 1 2 3", "1", "2", "3", undefined] 277 | 278 | handle_face_line([ result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ] ]); 279 | 280 | } else if ( ( result = face_pattern2.exec( line ) ) !== null ) { 281 | 282 | // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined] 283 | 284 | handle_face_line( 285 | [ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces 286 | [ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //uv 287 | ); 288 | 289 | } else if ( ( result = face_pattern3.exec( line ) ) !== null ) { 290 | 291 | // ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined] 292 | 293 | handle_face_line( 294 | [ result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ] ], //faces 295 | [ result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ] ], //uv 296 | [ result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ] ] //normal 297 | ); 298 | 299 | } else if ( ( result = face_pattern4.exec( line ) ) !== null ) { 300 | 301 | // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined] 302 | 303 | handle_face_line( 304 | [ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces 305 | [ ], //uv 306 | [ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //normal 307 | ); 308 | 309 | } else if ( /^o /.test( line ) ) { 310 | 311 | // object 312 | 313 | meshN(); 314 | face_offset = face_offset + vertices.length; 315 | vertices = []; 316 | object = new THREE.Object3D(); 317 | object.name = line.substring( 2 ).trim(); 318 | group.add( object ); 319 | 320 | } else if ( /^g /.test( line ) ) { 321 | 322 | // group 323 | 324 | meshN( line.substring( 2 ).trim(), undefined ); 325 | 326 | } else if ( /^usemtl /.test( line ) ) { 327 | 328 | // material 329 | 330 | meshN( undefined, line.substring( 7 ).trim() ); 331 | 332 | } else if ( /^mtllib /.test( line ) ) { 333 | 334 | // mtl file 335 | 336 | if ( mtllibCallback ) { 337 | 338 | var mtlfile = line.substring( 7 ); 339 | mtlfile = mtlfile.trim(); 340 | mtllibCallback( mtlfile ); 341 | 342 | } 343 | 344 | } else if ( /^s /.test( line ) ) { 345 | 346 | // Smooth shading 347 | 348 | } else { 349 | 350 | console.log( "THREE.OBJMTLLoader: Unhandled line " + line ); 351 | 352 | } 353 | 354 | } 355 | 356 | //Add last object 357 | meshN(undefined, undefined); 358 | 359 | return group; 360 | 361 | } 362 | 363 | }; 364 | 365 | THREE.EventDispatcher.prototype.apply( THREE.OBJMTLLoader.prototype ); 366 | -------------------------------------------------------------------------------- /examples/webgl_demo/static/js/STLLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author aleeper / http://adamleeper.com/ 3 | * @author mrdoob / http://mrdoob.com/ 4 | * @author gero3 / https://github.com/gero3 5 | * 6 | * Description: A THREE loader for STL ASCII files, as created by Solidworks and other CAD programs. 7 | * 8 | * Supports both binary and ASCII encoded files, with automatic detection of type. 9 | * 10 | * Limitations: 11 | * Binary decoding supports "Magics" color format (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL). 12 | * There is perhaps some question as to how valid it is to always assume little-endian-ness. 13 | * ASCII decoding assumes file is UTF-8. Seems to work for the examples... 14 | * 15 | * Usage: 16 | * var loader = new THREE.STLLoader(); 17 | * loader.load( './models/stl/slotted_disk.stl', function ( geometry ) { 18 | * scene.add( new THREE.Mesh( geometry ) ); 19 | * }); 20 | * 21 | * For binary STLs geometry might contain colors for vertices. To use it: 22 | * // use the same code to load STL as above 23 | * if (geometry.hasColors) { 24 | * material = new THREE.MeshPhongMaterial({ opacity: geometry.alpha, vertexColors: THREE.VertexColors }); 25 | * } else { .... } 26 | * var mesh = new THREE.Mesh( geometry, material ); 27 | */ 28 | 29 | 30 | THREE.STLLoader = function ( manager ) { 31 | 32 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 33 | 34 | }; 35 | 36 | THREE.STLLoader.prototype = { 37 | 38 | constructor: THREE.STLLoader, 39 | 40 | load: function ( url, onLoad, onProgress, onError ) { 41 | 42 | var scope = this; 43 | 44 | var loader = new THREE.XHRLoader( scope.manager ); 45 | loader.setCrossOrigin( this.crossOrigin ); 46 | loader.setResponseType('arraybuffer'); 47 | loader.load( url, function ( text ) { 48 | 49 | onLoad( scope.parse( text ) ); 50 | 51 | }, onProgress, onError ); 52 | 53 | }, 54 | 55 | parse: function ( data ) { 56 | 57 | var isBinary = function () { 58 | 59 | var expect, face_size, n_faces, reader; 60 | reader = new DataView( binData ); 61 | face_size = (32 / 8 * 3) + ((32 / 8 * 3) * 3) + (16 / 8); 62 | n_faces = reader.getUint32(80, true); 63 | expect = 80 + (32 / 8) + (n_faces * face_size); 64 | 65 | if ( expect === reader.byteLength ) { 66 | 67 | return true; 68 | 69 | } 70 | 71 | // some binary files will have different size from expected, 72 | // checking characters higher than ASCII to confirm is binary 73 | var fileLength = reader.byteLength; 74 | for ( var index = 0; index < fileLength; index ++ ) { 75 | 76 | if ( reader.getUint8(index, false) > 127 ) { 77 | 78 | return true; 79 | 80 | } 81 | 82 | } 83 | 84 | return false; 85 | 86 | }; 87 | 88 | var binData = this.ensureBinary( data ); 89 | 90 | return isBinary() 91 | ? this.parseBinary( binData ) 92 | : this.parseASCII( this.ensureString( data ) ); 93 | 94 | }, 95 | 96 | parseBinary: function ( data ) { 97 | 98 | var reader = new DataView( data ); 99 | var faces = reader.getUint32( 80, true ); 100 | 101 | var r, g, b, hasColors = false, colors; 102 | var defaultR, defaultG, defaultB, alpha; 103 | 104 | // process STL header 105 | // check for default color in header ("COLOR=rgba" sequence). 106 | 107 | for ( var index = 0; index < 80 - 10; index ++ ) { 108 | 109 | if ((reader.getUint32(index, false) == 0x434F4C4F /*COLO*/) && 110 | (reader.getUint8(index + 4) == 0x52 /*'R'*/) && 111 | (reader.getUint8(index + 5) == 0x3D /*'='*/)) { 112 | 113 | hasColors = true; 114 | colors = new Float32Array( faces * 3 * 3); 115 | 116 | defaultR = reader.getUint8(index + 6) / 255; 117 | defaultG = reader.getUint8(index + 7) / 255; 118 | defaultB = reader.getUint8(index + 8) / 255; 119 | alpha = reader.getUint8(index + 9) / 255; 120 | } 121 | } 122 | 123 | var dataOffset = 84; 124 | var faceLength = 12 * 4 + 2; 125 | 126 | var offset = 0; 127 | 128 | var geometry = new THREE.BufferGeometry(); 129 | 130 | var vertices = new Float32Array( faces * 3 * 3 ); 131 | var normals = new Float32Array( faces * 3 * 3 ); 132 | 133 | for ( var face = 0; face < faces; face ++ ) { 134 | 135 | var start = dataOffset + face * faceLength; 136 | var normalX = reader.getFloat32(start, true); 137 | var normalY = reader.getFloat32(start + 4, true); 138 | var normalZ = reader.getFloat32(start + 8, true); 139 | 140 | if (hasColors) { 141 | 142 | var packedColor = reader.getUint16(start + 48, true); 143 | 144 | if ((packedColor & 0x8000) === 0) { // facet has its own unique color 145 | 146 | r = (packedColor & 0x1F) / 31; 147 | g = ((packedColor >> 5) & 0x1F) / 31; 148 | b = ((packedColor >> 10) & 0x1F) / 31; 149 | } else { 150 | 151 | r = defaultR; 152 | g = defaultG; 153 | b = defaultB; 154 | } 155 | } 156 | 157 | for ( var i = 1; i <= 3; i ++ ) { 158 | 159 | var vertexstart = start + i * 12; 160 | 161 | vertices[ offset ] = reader.getFloat32( vertexstart, true ); 162 | vertices[ offset + 1 ] = reader.getFloat32( vertexstart + 4, true ); 163 | vertices[ offset + 2 ] = reader.getFloat32( vertexstart + 8, true ); 164 | 165 | normals[ offset ] = normalX; 166 | normals[ offset + 1 ] = normalY; 167 | normals[ offset + 2 ] = normalZ; 168 | 169 | if (hasColors) { 170 | colors[ offset ] = r; 171 | colors[ offset + 1 ] = g; 172 | colors[ offset + 2 ] = b; 173 | } 174 | 175 | offset += 3; 176 | 177 | } 178 | 179 | } 180 | 181 | geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); 182 | geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); 183 | 184 | if (hasColors) { 185 | geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) ); 186 | geometry.hasColors = true; 187 | geometry.alpha = alpha; 188 | } 189 | 190 | return geometry; 191 | 192 | }, 193 | 194 | parseASCII: function ( data ) { 195 | 196 | var geometry, length, normal, patternFace, patternNormal, patternVertex, result, text; 197 | geometry = new THREE.Geometry(); 198 | patternFace = /facet([\s\S]*?)endfacet/g; 199 | 200 | while ( ( result = patternFace.exec( data ) ) !== null ) { 201 | 202 | text = result[0]; 203 | patternNormal = /normal[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g; 204 | 205 | while ( ( result = patternNormal.exec( text ) ) !== null ) { 206 | 207 | normal = new THREE.Vector3( parseFloat( result[ 1 ] ), parseFloat( result[ 3 ] ), parseFloat( result[ 5 ] ) ); 208 | 209 | } 210 | 211 | patternVertex = /vertex[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g; 212 | 213 | while ( ( result = patternVertex.exec( text ) ) !== null ) { 214 | 215 | geometry.vertices.push( new THREE.Vector3( parseFloat( result[ 1 ] ), parseFloat( result[ 3 ] ), parseFloat( result[ 5 ] ) ) ); 216 | 217 | } 218 | 219 | length = geometry.vertices.length; 220 | 221 | geometry.faces.push( new THREE.Face3( length - 3, length - 2, length - 1, normal ) ); 222 | 223 | } 224 | 225 | geometry.computeBoundingBox(); 226 | geometry.computeBoundingSphere(); 227 | 228 | return geometry; 229 | 230 | }, 231 | 232 | ensureString: function ( buf ) { 233 | 234 | if (typeof buf !== "string") { 235 | var array_buffer = new Uint8Array(buf); 236 | var str = ''; 237 | for (var i = 0; i < buf.byteLength; i ++) { 238 | str += String.fromCharCode(array_buffer[i]); // implicitly assumes little-endian 239 | } 240 | return str; 241 | } else { 242 | return buf; 243 | } 244 | 245 | }, 246 | 247 | ensureBinary: function ( buf ) { 248 | 249 | if (typeof buf === "string") { 250 | var array_buffer = new Uint8Array(buf.length); 251 | for (var i = 0; i < buf.length; i ++) { 252 | array_buffer[i] = buf.charCodeAt(i) & 0xff; // implicitly assumes little-endian 253 | } 254 | return array_buffer.buffer || array_buffer; 255 | } else { 256 | return buf; 257 | } 258 | 259 | } 260 | 261 | }; 262 | 263 | if ( typeof DataView === 'undefined') { 264 | 265 | DataView = function(buffer, byteOffset, byteLength) { 266 | 267 | this.buffer = buffer; 268 | this.byteOffset = byteOffset || 0; 269 | this.byteLength = byteLength || buffer.byteLength || buffer.length; 270 | this._isString = typeof buffer === "string"; 271 | 272 | } 273 | 274 | DataView.prototype = { 275 | 276 | _getCharCodes:function(buffer,start,length) { 277 | start = start || 0; 278 | length = length || buffer.length; 279 | var end = start + length; 280 | var codes = []; 281 | for (var i = start; i < end; i ++) { 282 | codes.push(buffer.charCodeAt(i) & 0xff); 283 | } 284 | return codes; 285 | }, 286 | 287 | _getBytes: function (length, byteOffset, littleEndian) { 288 | 289 | var result; 290 | 291 | // Handle the lack of endianness 292 | if (littleEndian === undefined) { 293 | 294 | littleEndian = this._littleEndian; 295 | 296 | } 297 | 298 | // Handle the lack of byteOffset 299 | if (byteOffset === undefined) { 300 | 301 | byteOffset = this.byteOffset; 302 | 303 | } else { 304 | 305 | byteOffset = this.byteOffset + byteOffset; 306 | 307 | } 308 | 309 | if (length === undefined) { 310 | 311 | length = this.byteLength - byteOffset; 312 | 313 | } 314 | 315 | // Error Checking 316 | if (typeof byteOffset !== 'number') { 317 | 318 | throw new TypeError('DataView byteOffset is not a number'); 319 | 320 | } 321 | 322 | if (length < 0 || byteOffset + length > this.byteLength) { 323 | 324 | throw new Error('DataView length or (byteOffset+length) value is out of bounds'); 325 | 326 | } 327 | 328 | if (this.isString) { 329 | 330 | result = this._getCharCodes(this.buffer, byteOffset, byteOffset + length); 331 | 332 | } else { 333 | 334 | result = this.buffer.slice(byteOffset, byteOffset + length); 335 | 336 | } 337 | 338 | if (!littleEndian && length > 1) { 339 | 340 | if (!(result instanceof Array)) { 341 | 342 | result = Array.prototype.slice.call(result); 343 | 344 | } 345 | 346 | result.reverse(); 347 | } 348 | 349 | return result; 350 | 351 | }, 352 | 353 | // Compatibility functions on a String Buffer 354 | 355 | getFloat64: function (byteOffset, littleEndian) { 356 | 357 | var b = this._getBytes(8, byteOffset, littleEndian), 358 | 359 | sign = 1 - (2 * (b[7] >> 7)), 360 | exponent = ((((b[7] << 1) & 0xff) << 3) | (b[6] >> 4)) - ((1 << 10) - 1), 361 | 362 | // Binary operators such as | and << operate on 32 bit values, using + and Math.pow(2) instead 363 | mantissa = ((b[6] & 0x0f) * Math.pow(2, 48)) + (b[5] * Math.pow(2, 40)) + (b[4] * Math.pow(2, 32)) + 364 | (b[3] * Math.pow(2, 24)) + (b[2] * Math.pow(2, 16)) + (b[1] * Math.pow(2, 8)) + b[0]; 365 | 366 | if (exponent === 1024) { 367 | if (mantissa !== 0) { 368 | return NaN; 369 | } else { 370 | return sign * Infinity; 371 | } 372 | } 373 | 374 | if (exponent === -1023) { // Denormalized 375 | return sign * mantissa * Math.pow(2, -1022 - 52); 376 | } 377 | 378 | return sign * (1 + mantissa * Math.pow(2, -52)) * Math.pow(2, exponent); 379 | 380 | }, 381 | 382 | getFloat32: function (byteOffset, littleEndian) { 383 | 384 | var b = this._getBytes(4, byteOffset, littleEndian), 385 | 386 | sign = 1 - (2 * (b[3] >> 7)), 387 | exponent = (((b[3] << 1) & 0xff) | (b[2] >> 7)) - 127, 388 | mantissa = ((b[2] & 0x7f) << 16) | (b[1] << 8) | b[0]; 389 | 390 | if (exponent === 128) { 391 | if (mantissa !== 0) { 392 | return NaN; 393 | } else { 394 | return sign * Infinity; 395 | } 396 | } 397 | 398 | if (exponent === -127) { // Denormalized 399 | return sign * mantissa * Math.pow(2, -126 - 23); 400 | } 401 | 402 | return sign * (1 + mantissa * Math.pow(2, -23)) * Math.pow(2, exponent); 403 | }, 404 | 405 | getInt32: function (byteOffset, littleEndian) { 406 | var b = this._getBytes(4, byteOffset, littleEndian); 407 | return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]; 408 | }, 409 | 410 | getUint32: function (byteOffset, littleEndian) { 411 | return this.getInt32(byteOffset, littleEndian) >>> 0; 412 | }, 413 | 414 | getInt16: function (byteOffset, littleEndian) { 415 | return (this.getUint16(byteOffset, littleEndian) << 16) >> 16; 416 | }, 417 | 418 | getUint16: function (byteOffset, littleEndian) { 419 | var b = this._getBytes(2, byteOffset, littleEndian); 420 | return (b[1] << 8) | b[0]; 421 | }, 422 | 423 | getInt8: function (byteOffset) { 424 | return (this.getUint8(byteOffset) << 24) >> 24; 425 | }, 426 | 427 | getUint8: function (byteOffset) { 428 | return this._getBytes(1, byteOffset)[0]; 429 | } 430 | 431 | }; 432 | 433 | } 434 | -------------------------------------------------------------------------------- /examples/webgl_demo/static/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.5 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under the MIT license 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.5",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.5",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.5",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.5",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.5",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.5",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.5",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.5",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); -------------------------------------------------------------------------------- /examples/webgl_demo/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Adafruit BNO055 Absolute Orientation Sensor 10 | 11 | 12 | 13 | 14 | 20 | 21 | 25 | 26 | 27 | 30 |
31 |
32 |
33 |

Adafruit BNO055 Absolute Orientation Sensor Demo

34 |

Connecting...

35 |
36 |
37 |
38 |
39 |
40 |
41 |

Orientation (degrees):

42 |

Heading = 0

43 |

Roll = 0

44 |

Pitch = 0

45 |
46 |
47 |

Calibration:

48 |

(0=uncalibrated, 3=fully calibrated)

49 |

System = 0

50 |

Gyro = 0

51 |

Accelerometer = 0

52 |

Magnetometer = 0

53 |
54 |
55 |

Actions:

56 |
57 |
58 |
62 |
63 | 64 |
65 |
66 | 67 |
68 |
69 | 70 |
71 |
72 |
73 |
74 |
75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 289 | 290 | 291 | -------------------------------------------------------------------------------- /ez_setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Bootstrap setuptools installation 3 | 4 | To use setuptools in your package's setup.py, include this 5 | file in the same directory and add this to the top of your setup.py:: 6 | 7 | from ez_setup import use_setuptools 8 | use_setuptools() 9 | 10 | To require a specific version of setuptools, set a download 11 | mirror, or use an alternate download directory, simply supply 12 | the appropriate options to ``use_setuptools()``. 13 | 14 | This file can also be run as a script to install or upgrade setuptools. 15 | """ 16 | import os 17 | import shutil 18 | import sys 19 | import tempfile 20 | import zipfile 21 | import optparse 22 | import subprocess 23 | import platform 24 | import textwrap 25 | import contextlib 26 | 27 | from distutils import log 28 | 29 | try: 30 | from site import USER_SITE 31 | except ImportError: 32 | USER_SITE = None 33 | 34 | DEFAULT_VERSION = "3.5.1" 35 | DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/" 36 | 37 | def _python_cmd(*args): 38 | """ 39 | Return True if the command succeeded. 40 | """ 41 | args = (sys.executable,) + args 42 | return subprocess.call(args) == 0 43 | 44 | 45 | def _install(archive_filename, install_args=()): 46 | with archive_context(archive_filename): 47 | # installing 48 | log.warn('Installing Setuptools') 49 | if not _python_cmd('setup.py', 'install', *install_args): 50 | log.warn('Something went wrong during the installation.') 51 | log.warn('See the error message above.') 52 | # exitcode will be 2 53 | return 2 54 | 55 | 56 | def _build_egg(egg, archive_filename, to_dir): 57 | with archive_context(archive_filename): 58 | # building an egg 59 | log.warn('Building a Setuptools egg in %s', to_dir) 60 | _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) 61 | # returning the result 62 | log.warn(egg) 63 | if not os.path.exists(egg): 64 | raise IOError('Could not build the egg.') 65 | 66 | 67 | def get_zip_class(): 68 | """ 69 | Supplement ZipFile class to support context manager for Python 2.6 70 | """ 71 | class ContextualZipFile(zipfile.ZipFile): 72 | def __enter__(self): 73 | return self 74 | def __exit__(self, type, value, traceback): 75 | self.close 76 | return zipfile.ZipFile if hasattr(zipfile.ZipFile, '__exit__') else \ 77 | ContextualZipFile 78 | 79 | 80 | @contextlib.contextmanager 81 | def archive_context(filename): 82 | # extracting the archive 83 | tmpdir = tempfile.mkdtemp() 84 | log.warn('Extracting in %s', tmpdir) 85 | old_wd = os.getcwd() 86 | try: 87 | os.chdir(tmpdir) 88 | with get_zip_class()(filename) as archive: 89 | archive.extractall() 90 | 91 | # going in the directory 92 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 93 | os.chdir(subdir) 94 | log.warn('Now working in %s', subdir) 95 | yield 96 | 97 | finally: 98 | os.chdir(old_wd) 99 | shutil.rmtree(tmpdir) 100 | 101 | 102 | def _do_download(version, download_base, to_dir, download_delay): 103 | egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg' 104 | % (version, sys.version_info[0], sys.version_info[1])) 105 | if not os.path.exists(egg): 106 | archive = download_setuptools(version, download_base, 107 | to_dir, download_delay) 108 | _build_egg(egg, archive, to_dir) 109 | sys.path.insert(0, egg) 110 | 111 | # Remove previously-imported pkg_resources if present (see 112 | # https://bitbucket.org/pypa/setuptools/pull-request/7/ for details). 113 | if 'pkg_resources' in sys.modules: 114 | del sys.modules['pkg_resources'] 115 | 116 | import setuptools 117 | setuptools.bootstrap_install_from = egg 118 | 119 | 120 | def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 121 | to_dir=os.curdir, download_delay=15): 122 | to_dir = os.path.abspath(to_dir) 123 | rep_modules = 'pkg_resources', 'setuptools' 124 | imported = set(sys.modules).intersection(rep_modules) 125 | try: 126 | import pkg_resources 127 | except ImportError: 128 | return _do_download(version, download_base, to_dir, download_delay) 129 | try: 130 | pkg_resources.require("setuptools>=" + version) 131 | return 132 | except pkg_resources.DistributionNotFound: 133 | return _do_download(version, download_base, to_dir, download_delay) 134 | except pkg_resources.VersionConflict as VC_err: 135 | if imported: 136 | msg = textwrap.dedent(""" 137 | The required version of setuptools (>={version}) is not available, 138 | and can't be installed while this script is running. Please 139 | install a more recent version first, using 140 | 'easy_install -U setuptools'. 141 | 142 | (Currently using {VC_err.args[0]!r}) 143 | """).format(VC_err=VC_err, version=version) 144 | sys.stderr.write(msg) 145 | sys.exit(2) 146 | 147 | # otherwise, reload ok 148 | del pkg_resources, sys.modules['pkg_resources'] 149 | return _do_download(version, download_base, to_dir, download_delay) 150 | 151 | def _clean_check(cmd, target): 152 | """ 153 | Run the command to download target. If the command fails, clean up before 154 | re-raising the error. 155 | """ 156 | try: 157 | subprocess.check_call(cmd) 158 | except subprocess.CalledProcessError: 159 | if os.access(target, os.F_OK): 160 | os.unlink(target) 161 | raise 162 | 163 | def download_file_powershell(url, target): 164 | """ 165 | Download the file at url to target using Powershell (which will validate 166 | trust). Raise an exception if the command cannot complete. 167 | """ 168 | target = os.path.abspath(target) 169 | cmd = [ 170 | 'powershell', 171 | '-Command', 172 | "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" % vars(), 173 | ] 174 | _clean_check(cmd, target) 175 | 176 | def has_powershell(): 177 | if platform.system() != 'Windows': 178 | return False 179 | cmd = ['powershell', '-Command', 'echo test'] 180 | devnull = open(os.path.devnull, 'wb') 181 | try: 182 | try: 183 | subprocess.check_call(cmd, stdout=devnull, stderr=devnull) 184 | except Exception: 185 | return False 186 | finally: 187 | devnull.close() 188 | return True 189 | 190 | download_file_powershell.viable = has_powershell 191 | 192 | def download_file_curl(url, target): 193 | cmd = ['curl', url, '--silent', '--output', target] 194 | _clean_check(cmd, target) 195 | 196 | def has_curl(): 197 | cmd = ['curl', '--version'] 198 | devnull = open(os.path.devnull, 'wb') 199 | try: 200 | try: 201 | subprocess.check_call(cmd, stdout=devnull, stderr=devnull) 202 | except Exception: 203 | return False 204 | finally: 205 | devnull.close() 206 | return True 207 | 208 | download_file_curl.viable = has_curl 209 | 210 | def download_file_wget(url, target): 211 | cmd = ['wget', url, '--quiet', '--output-document', target] 212 | _clean_check(cmd, target) 213 | 214 | def has_wget(): 215 | cmd = ['wget', '--version'] 216 | devnull = open(os.path.devnull, 'wb') 217 | try: 218 | try: 219 | subprocess.check_call(cmd, stdout=devnull, stderr=devnull) 220 | except Exception: 221 | return False 222 | finally: 223 | devnull.close() 224 | return True 225 | 226 | download_file_wget.viable = has_wget 227 | 228 | def download_file_insecure(url, target): 229 | """ 230 | Use Python to download the file, even though it cannot authenticate the 231 | connection. 232 | """ 233 | try: 234 | from urllib.request import urlopen 235 | except ImportError: 236 | from urllib2 import urlopen 237 | src = dst = None 238 | try: 239 | src = urlopen(url) 240 | # Read/write all in one block, so we don't create a corrupt file 241 | # if the download is interrupted. 242 | data = src.read() 243 | dst = open(target, "wb") 244 | dst.write(data) 245 | finally: 246 | if src: 247 | src.close() 248 | if dst: 249 | dst.close() 250 | 251 | download_file_insecure.viable = lambda: True 252 | 253 | def get_best_downloader(): 254 | downloaders = [ 255 | download_file_powershell, 256 | download_file_curl, 257 | download_file_wget, 258 | download_file_insecure, 259 | ] 260 | 261 | for dl in downloaders: 262 | if dl.viable(): 263 | return dl 264 | 265 | def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 266 | to_dir=os.curdir, delay=15, downloader_factory=get_best_downloader): 267 | """ 268 | Download setuptools from a specified location and return its filename 269 | 270 | `version` should be a valid setuptools version number that is available 271 | as an egg for download under the `download_base` URL (which should end 272 | with a '/'). `to_dir` is the directory where the egg will be downloaded. 273 | `delay` is the number of seconds to pause before an actual download 274 | attempt. 275 | 276 | ``downloader_factory`` should be a function taking no arguments and 277 | returning a function for downloading a URL to a target. 278 | """ 279 | # making sure we use the absolute path 280 | to_dir = os.path.abspath(to_dir) 281 | zip_name = "setuptools-%s.zip" % version 282 | url = download_base + zip_name 283 | saveto = os.path.join(to_dir, zip_name) 284 | if not os.path.exists(saveto): # Avoid repeated downloads 285 | log.warn("Downloading %s", url) 286 | downloader = downloader_factory() 287 | downloader(url, saveto) 288 | return os.path.realpath(saveto) 289 | 290 | def _build_install_args(options): 291 | """ 292 | Build the arguments to 'python setup.py install' on the setuptools package 293 | """ 294 | return ['--user'] if options.user_install else [] 295 | 296 | def _parse_args(): 297 | """ 298 | Parse the command line for options 299 | """ 300 | parser = optparse.OptionParser() 301 | parser.add_option( 302 | '--user', dest='user_install', action='store_true', default=False, 303 | help='install in user site package (requires Python 2.6 or later)') 304 | parser.add_option( 305 | '--download-base', dest='download_base', metavar="URL", 306 | default=DEFAULT_URL, 307 | help='alternative URL from where to download the setuptools package') 308 | parser.add_option( 309 | '--insecure', dest='downloader_factory', action='store_const', 310 | const=lambda: download_file_insecure, default=get_best_downloader, 311 | help='Use internal, non-validating downloader' 312 | ) 313 | parser.add_option( 314 | '--version', help="Specify which version to download", 315 | default=DEFAULT_VERSION, 316 | ) 317 | options, args = parser.parse_args() 318 | # positional arguments are ignored 319 | return options 320 | 321 | def main(): 322 | """Install or upgrade setuptools and EasyInstall""" 323 | options = _parse_args() 324 | archive = download_setuptools( 325 | version=options.version, 326 | download_base=options.download_base, 327 | downloader_factory=options.downloader_factory, 328 | ) 329 | return _install(archive, _build_install_args(options)) 330 | 331 | if __name__ == '__main__': 332 | sys.exit(main()) 333 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | try: 2 | # Try using ez_setup to install setuptools if not already installed. 3 | from ez_setup import use_setuptools 4 | use_setuptools() 5 | except ImportError: 6 | # Ignore import error and assume Python 3 which already has setuptools. 7 | pass 8 | 9 | from setuptools import setup, find_packages 10 | 11 | classifiers = ['Development Status :: 4 - Beta', 12 | 'Operating System :: POSIX :: Linux', 13 | 'License :: OSI Approved :: MIT License', 14 | 'Intended Audience :: Developers', 15 | 'Programming Language :: Python :: 2.7', 16 | 'Programming Language :: Python :: 3', 17 | 'Topic :: Software Development', 18 | 'Topic :: System :: Hardware'] 19 | 20 | setup(name = 'Adafruit_BNO055', 21 | version = '1.0.2', 22 | author = 'Tony DiCola', 23 | author_email = 'tdicola@adafruit.com', 24 | description = 'Library for accessing the Bosch BNO055 absolute orientation sensor on a Raspberry Pi or Beaglebone Black.', 25 | license = 'MIT', 26 | classifiers = classifiers, 27 | url = 'https://github.com/adafruit/Adafruit_Python_BNO055/', 28 | dependency_links = ['https://github.com/adafruit/Adafruit_Python_GPIO/tarball/master#egg=Adafruit-GPIO-0.9.3'], 29 | install_requires = ['Adafruit-GPIO>=0.9.3', 'pyserial'], 30 | packages = find_packages()) 31 | --------------------------------------------------------------------------------