├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── LICENSE ├── README.md └── examples └── line_extraction ├── README.md ├── data └── example_1.js ├── index.html ├── js ├── components │ ├── Data.js │ ├── EventDispatcher.js │ ├── Graphics.js │ ├── Perception.js │ ├── Plotting.js │ ├── Processing.js │ └── Utils.js ├── main.js └── namespace.js └── style └── style-helper-utils.css /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Help 2 | The [issues](https://github.com/scanse/sweep-learning-examples/issues) section is for bug reports and feature requests. If you need help with a project, please use the [community](http://community.scanse.io/) forum. 3 | 4 | --- 5 | # Bugs 6 | #### Before reporting a bug 7 | 8 | 1. Search [issue tracker](https://github.com/scanse/sweep-learning-examples/issues) for similar issues. 9 | 2. Make sure you are using the latest version of the code, and that you have thoroughly reviewed all provided documentation. 10 | 11 | 12 | #### How to report a bug 13 | 1. Create a new issue on the [issue tracker](https://github.com/scanse/sweep-learning-examples/issues). 14 | 2. Describe the problem in detail. Explain what happened, and what you expected would happen. 15 | 3. If it makes things more clear, include an annotated screenshot. 16 | 17 | --- 18 | # Contribution 19 | The `sweep-learning-examples` are a learning resource for the community. Learning material will evolve more quickly with community contribution! We will work hard to integrate valuable changes, improvements and features. To make the process more efficient, here are some general steps to contribute. 20 | 21 | #### How to contribute 22 | 23 | 1. Login or create a GitHub account. 24 | 2. Fork the repository on GitHub. 25 | 3. Make changes to your fork of the repository. 26 | 4. Check the [Contribution Guidelines](PULL_REQUEST_TEMPLATE.md) for pull requests and make sure your modifications adhere to the guidelines. 27 | 5. Submit your modifications as a new pull request [here](https://github.com/scanse/sweep-learning-examples/pulls). -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | #### Scope of changes 16 | 21 | 22 | #### Known Limitations 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Scanse 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sweep-learning-examples 2 | A collection of learning examples relevant to 2D LiDAR data. 3 | 4 | 5 | ## Examples: 6 | - [Line Extraction](/examples/line_extraction) 7 | 8 | 9 | ## See the [Wiki](https://github.com/scanse/sweep-learning-examples/wiki) for Documentation 10 | -------------------------------------------------------------------------------- /examples/line_extraction/README.md: -------------------------------------------------------------------------------- 1 | # Line Extraction Learning Example 2 | 3 | ## See the [Wiki](https://github.com/scanse/sweep-learning-examples/wiki) for Documentation 4 | 5 | ## Quickstart: 6 | 7 | 1. Retrieve the source code 8 | ``` 9 | git clone https://github.com/scanse/sweep-learning-examples 10 | ``` 11 | 2. Open open `index.html` (`sweep-learning-examples/examples/line_extraction/index.html`) in a WebGL compatible browser such as google chrome. 12 | 13 | ## Compatibility: 14 | The example is designed to run in a web browser without requiring a server or any kind of modifications to file access. However, your web browser must be able to run WebGL. You can check that here: [https://get.webgl.org/](https://get.webgl.org/) 15 | 16 | 17 | ## File Structure: 18 | - `data/`: contains the recorded scan data used to visualize the algorithms (json data stored as string in js file). 19 | - `js`: the source code for the application 20 | - `components/`: the applications components/modules 21 | - `namespace.js`: defines the application namespace + structure of components/modules 22 | - `main.js`: control logic and entry point for the application 23 | - `lib`: third party libraries 24 | - `style`: css helpers 25 | - `index.html`: the HTML page 26 | 27 | ## Experimenting with Parameters 28 | The easiest way to explore the effects of various parameters is to tinker with them and visualize the effects. To alter the parameters used in the example, simply adjust the values specified in the `initLineExtractor()` method from the `LineExtractionApp.Visualizer` module. For descriptions of each parameter, see the section on [Line Extraction](https://github.com/scanse/sweep-learning-examples/wiki/Line-Extraction). -------------------------------------------------------------------------------- /examples/line_extraction/data/example_1.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Sample data recording to be played back by the application. 3 | * 4 | * This is a javascript file which defines a string variable containing the 5 | * contents of a JSON file exported from the Sweep Visualizer. Data is stored 6 | * this way to avoid cross origin requests, and allow this example to run without 7 | * any special access. 8 | * 9 | * To use a different recording: 10 | * 1. Export or convert the recording to .json format using the Sweep Visualizer. 11 | * 2. Copy the contents of the exported file. 12 | * 3. Replace the assignment value of EXAMPLE_RECORDING_1_JSON_DATA with the 13 | * copied contents of the recording file. Be sure the contents are pasted 14 | * as a string (ie: inside 'single' or "double" quotations). 15 | */ 16 | var EXAMPLE_RECORDING_1_JSON_DATA = '{"bSensorIsMobile":false,"bLogTimeStampPerSweep":true,"Sweeps":[{"TimeStamp":1496454229718,"SensorReading_Angles":[1.5,2.375,3.1875,4.0625,5.0625,6,7,7.9375,10.6875,12,16.875,20.1875,21.0625,22.25,23.3125,24.9375,29.75,34.625,35.8125,36.8125,37.875,41.5625,42.5625,43.75,48.5,49.5,50.5,51.5625,52.5625,53.8125,54.8125,55.8125,57.375,58.375,59.375,60.375,61.375,62.4375,65,65.9375,66.5625,67.5625,68.5625,69.5,70.5625,71.4375,72.25,73.125,73.9375,74.8125,75.625,76.625,77.625,78.5,79.375,80.1875,81.0625,81.875,82.75,83.75,84.6875,85.9375,86.75,87.6875,88.5625,89.375,90.25,91.25,92.25,93.25,94.625,95.875,97.0625,98.0625,99.0625,100.3125,103.4375,106.25,107.25,108.25,109.375,110.6875,111.75,112.6875,113.9375,115.0625,116.375,118.75,119.75,120.75,121.8125,123.1875,128.1875,129.125,130.1875,131.25,132.5625,133.6875,134.75,137.8125,138.6875,139.5,140.5,141.5,142.4375,143.3125,144.125,145.125,146.125,147,147.8125,148.8125,149.75,150.75,153.5,156.4375,157.3125,158.1875,159.0625,159.875,160.875,161.8125,162.8125,163.8125,164.75,165.75,166.75,167.8125,168.875,169.9375,171,172.0625,173.125,174.1875,175.125,175.9375,176.9375,177.9375,179.1875,180.1875,183.875,184.875,185.6875,186.6875,187.5,188.5,189.5,190.4375,191.3125,192.3125,193.25,194.25,195.25,196.125,197,198.25,199.1875,200.1875,201.1875,202.25,203.1875,204.1875,205.25,206.1875,207.375,208.5625,209.5625,210.625,211.5,212.5,213.5,214.5,215.5,216.5625,217.625,218.625,219.75,220.75,221.75,222.75,223.8125,224.625,225.5,226.375,227.375,228.3125,229.375,230.4375,231.5,232.5625,233.625,234.6875,235.75,236.8125,237.875,238.9375,240,241.0625,242.25,243.0625,243.9375,244.8125,245.75,246.875,247.75,248.75,249.75,250.6875,251.5625,252.375,253.4375,254.375,255.25,256.25,257.25,258.0625,258.9375,259.9375,260.875,261.75,262.5625,263.4375,264.0625,264.9375,265.75,266.75,268.0625,269.0625,270,270.8125,271.6875,272.5625,273.4375,274.25,275.25,276.3125,277.3125,278.3125,279.375,280.375,281.375,282.625,283.625,284.8125,285.9375,287.1875,288.5,289.875,293.4375,294.5,295.5,296.4375,297.3125,298.125,299,300,301,301.9375,303,304,305,306.0625,307.0625,308.25,309.125,309.9375,310.9375,311.9375,312.9375,313.9375,314.8125,315.6875,316.5625,317.375,318.25,319.0625,319.9375,320.9375,321.8125,322.6875,323.8125,324.8125,325.8125,326.75,327.5625,328.5625,329.4375,330.25,331.25,336.125,340.0625,342.375,343.375,344.375,345.375,346.4375,347.3125,348.3125,349.3125,350.375,351.4375,352.5,353.5625,354.625,355.6875,356.75,357.75,358.8125,359.875],"SensorReading_Radii":[183,191,188,193,196,192,190,196,607,576,619,688,695,699,708,693,691,688,280,652,632,607,587,574,1,218,327,336,346,316,341,376,391,404,417,430,444,451,450,445,442,438,433,415,428,425,424,421,424,423,420,399,351,414,414,414,414,412,411,266,377,354,249,246,248,251,252,255,254,253,360,409,419,409,410,415,325,401,438,444,439,446,446,456,454,436,444,475,485,489,444,467,526,551,565,574,566,529,542,145,158,155,156,152,156,160,164,194,200,200,197,194,193,207,226,267,272,274,273,274,292,307,325,377,356,372,499,511,510,510,507,509,517,577,602,601,598,555,548,528,215,189,173,156,162,166,159,116,103,107,121,113,112,110,109,114,114,116,143,169,165,165,167,166,151,153,169,180,191,191,185,188,180,183,174,171,173,175,179,152,161,251,256,256,263,258,263,260,267,265,264,267,272,271,273,279,266,267,263,265,267,270,273,286,288,286,283,282,280,277,277,278,274,275,275,273,272,266,263,264,269,268,268,268,265,263,271,261,268,268,268,269,268,270,263,197,169,150,138,135,135,136,136,140,137,143,141,147,147,290,302,306,312,313,316,322,325,298,285,303,313,337,345,348,347,346,345,342,340,342,339,340,338,338,338,337,336,325,270,269,312,327,322,316,313,310,306,301,304,628,632,634,633,631,642,644,642,643,641,639,639,637,634,615,617,615,618,631,626],"SensorReading_SignalStrength":[167,199,199,199,191,199,199,199,98,167,40,84,199,191,191,159,40,65,159,199,191,72,183,191,25,199,191,199,199,199,183,191,167,199,199,199,191,191,112,199,199,191,183,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,183,183,199,199,199,199,199,199,199,199,199,191,183,167,191,191,191,98,98,199,191,183,191,191,199,191,167,183,126,199,199,191,191,40,199,191,191,167,159,183,98,199,199,199,199,199,199,199,199,199,199,199,191,199,199,98,84,199,199,199,191,191,199,199,191,191,175,175,191,191,191,191,191,175,183,199,199,199,191,159,191,84,199,199,199,199,191,191,191,199,199,199,191,199,199,199,191,199,199,191,183,191,191,191,183,175,183,191,183,199,191,191,191,183,183,183,191,191,191,199,199,199,199,199,199,199,191,191,191,191,191,191,191,183,183,183,191,191,183,191,191,199,199,199,199,199,199,199,199,199,191,191,199,199,199,199,199,199,191,199,199,199,199,199,199,199,191,175,191,199,199,199,199,199,199,199,191,199,199,191,191,191,183,175,167,167,175,167,159,84,167,199,199,199,199,199,199,199,199,191,191,191,183,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,199,199,199,191,191,199,199,199,199,199,191,50,70,126,199,199,199,191,191,191,191,183,183,191,191,191,183,183,191,183,191]},{"TimeStamp":1496454230223,"SensorReading_Angles":[2.4375,3.4375,4.4375,5.375,6.3125,7.3125,9.0625,10.1875,11.4375,14.9375,19.625,20.625,21.625,22.6875,23.75,28.5625,33.5625,35.25,36.25,37.25,40.9375,41.875,42.9375,44.25,49.1875,50.375,51.375,52.3125,53.4375,54.75,55.6875,58.3125,59.3125,60.375,61.4375,62.3125,64.8125,65.8125,66.5,67.5,68.4375,69.5,70.375,71.1875,72.0625,72.875,73.75,74.5625,75.4375,76.25,77.25,78.25,79.0625,79.9375,80.75,81.625,82.4375,83.6875,84.875,86,86.875,87.625,88.625,89.625,90.625,91.5625,92.4375,93.25,94.5,95.5,96.8125,97.8125,98.875,99.875,101.4375,102.8125,104.1875,107,108,109,109.9375,111,112.0625,112.9375,115.75,118.5,119.4375,120.5,121.4375,122.4375,125.5625,129,130,131.0625,132.5,133.6875,135.875,136.8125,137.6875,138.5,139.375,140.25,141.25,142.1875,143.125,144,144.875,145.6875,146.5625,147.375,148.25,149.125,150.125,151.125,152.25,155.125,156.1875,157.1875,158.1875,159.1875,160,160.875,161.875,162.9375,164,166.5,167.4375,168.5,169.5625,170.625,171.6875,172.75,173.75,174.8125,176.125,177.25,178.1875,179.25,180.3125,181.375,182.4375,183.4375,184.375,185.1875,186.0625,187.0625,188,189.0625,190,190.9375,191.9375,193,194.0625,195.0625,196.0625,197,198,199,200.0625,201.125,202.125,203.1875,204.25,205.3125,206.375,207.375,208.4375,209.5,210.5625,211.5625,212.625,213.6875,214.75,215.75,216.8125,217.875,218.9375,220.1875,221.125,221.9375,222.9375,223.9375,224.9375,225.9375,227,228.0625,229.125,230.1875,231.25,232.3125,233.375,234.4375,235.4375,236.5,237.5,238.6875,239.6875,240.6875,241.875,242.75,243.625,244.625,245.5625,246.5625,247.5625,248.5,249.5,250.5,251.5,252.5,253.375,254.375,255.375,256.375,257.25,258.0625,258.9375,259.8125,260.625,261.5,262.375,263.1875,263.875,264.875,265.875,266.875,267.75,268.625,269.5,270.3125,271.1875,272.0625,273.0625,274.125,275.1875,276.25,277.1875,278.1875,279.375,280.375,281.4375,282.75,283.9375,285.1875,288.4375,292.5,293.3125,294.1875,295,296,297,298,299,299.9375,300.875,301.875,302.875,303.9375,304.875,305.6875,306.5625,307.4375,308.4375,309.375,310.375,311.25,312.25,313.1875,314.1875,315.0625,316.0625,316.875,317.75,318.75,319.625,320.625,321.625,322.625,323.5625,324.5,325.5,326.5,327.375,328.375,333.125,334.125,335.125,336.1875,337.25,338.25,339.3125,340.25,341.3125,342.25,343.25,344.25,345.3125,346.375,347.375,348.4375,349.5,350.5625,351.625,352.6875,353.6875,354.6875,355.75,356.75,357.6875,358.9375],"SensorReading_Radii":[188,189,198,193,190,193,628,608,575,572,665,689,697,701,709,698,686,687,653,636,605,584,572,568,248,326,340,346,317,341,380,402,417,432,445,457,449,444,442,436,428,421,424,428,423,420,422,420,420,415,354,388,416,416,414,413,414,308,336,385,250,247,247,250,254,255,252,253,325,411,409,408,409,418,385,328,370,405,443,439,444,446,451,457,442,475,484,487,480,491,477,558,564,569,560,495,126,158,159,157,155,152,154,159,165,193,197,196,192,192,190,197,205,224,213,248,273,273,273,272,294,307,325,348,371,510,508,508,506,509,514,520,507,512,507,513,516,540,601,606,226,208,175,161,157,163,157,132,107,104,113,110,109,108,114,115,118,113,117,113,110,116,116,118,123,127,128,120,143,179,186,178,187,184,177,195,189,201,154,150,219,253,259,260,257,257,263,259,266,265,269,271,270,276,271,274,266,266,267,268,269,280,287,286,284,283,280,280,279,277,277,275,274,272,270,271,269,267,268,269,269,268,265,264,264,267,268,269,269,270,269,270,270,201,178,154,143,130,133,136,143,137,138,135,144,193,304,307,310,313,316,321,325,327,287,281,291,327,343,349,346,344,344,343,343,340,339,340,338,335,290,267,266,320,336,334,327,325,319,316,312,310,304,301,685,677,672,672,665,663,659,655,655,651,648,647,646,643,640,639,640,637,638,628,618,633,628,639,638,565],"SensorReading_SignalStrength":[98,199,199,199,199,199,199,167,167,159,70,199,191,199,191,50,50,159,191,191,72,183,183,183,35,167,191,199,191,183,191,112,191,191,183,199,112,191,199,199,191,183,199,199,199,199,199,199,199,199,191,199,199,199,199,199,199,199,191,191,199,199,199,199,199,199,199,199,199,199,167,175,191,175,159,191,183,112,199,183,191,191,191,199,112,98,199,199,199,191,98,84,191,191,167,167,167,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,183,199,98,183,199,199,199,199,199,191,199,191,112,191,183,191,191,175,183,191,175,183,167,183,183,191,191,183,191,191,199,199,199,191,183,199,199,199,191,191,191,191,191,191,183,183,199,191,191,191,191,183,191,191,199,183,191,191,191,191,191,183,191,183,183,199,199,191,191,199,199,191,191,191,191,191,191,191,191,183,191,199,175,183,191,199,199,199,199,199,191,199,199,199,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,191,199,199,199,199,199,199,199,199,191,191,191,191,183,183,183,175,167,159,183,98,70,199,199,199,199,191,191,191,199,199,191,199,183,199,199,199,199,199,199,199,199,199,199,199,191,191,199,199,191,191,191,191,199,199,191,191,199,199,191,55,183,191,191,191,191,191,191,191,199,191,191,183,175,183,191,191,191,191,191,199,199,191,199,199,175]},{"TimeStamp":1496454230727,"SensorReading_Angles":[0.1875,4.6875,7.375,8.375,9.4375,10.5,11.5,12.5,13.5625,14.625,15.6875,16.75,17.8125,18.8125,19.8125,20.875,22.25,23.25,24.375,25.4375,26.4375,27.4375,28.4375,29.4375,30.4375,31.375,32.3125,34,36.5625,37.625,38.5625,39.5625,40.5625,43.125,44.375,45.6875,46.75,47.75,48.6875,49.625,50.875,52.0625,53.0625,53.875,54.875,55.9375,56.8125,57.8125,58.8125,59.875,60.9375,62,63.0625,64.125,65.1875,66,67.0625,68,68.9375,69.9375,70.9375,72,72.875,73.875,74.875,75.875,76.9375,77.9375,78.875,79.875,80.875,81.875,82.875,83.9375,84.8125,85.75,87.125,89.875,90.8125,92.1875,93.3125,94.5625,97.9375,98.9375,101.375,102.375,103.375,104.4375,105.3125,106.3125,107.3125,108.375,109.4375,110.375,111.3125,112.3125,113.25,114.125,115.0625,116.0625,117.125,118.1875,119.25,120.3125,122.0625,123.0625,124,125,126,127.1875,128.3125,129.5,134.5,135.4375,136.4375,137.4375,138.8125,139.8125,141.125,142.3125,143.375,144.375,145.5625,148.3125,149.3125,150.375,151.3125,152.3125,153.25,154.125,155.0625,156.0625,157,158,159,160.1875,162.4375,163.4375,164.4375,165.4375,166.375,167.625,168.75,169.8125,170.75,171.5625,172.75,173.75,174.8125,176.125,178.625,179.625,180.625,181.5625,182.5625,183.625,184.5,185.375,186.1875,187.1875,188.1875,189.125,190.125,191.1875,192.0625,193.0625,194.0625,194.9375,195.9375,196.8125,197.6875,198.875,199.75,200.75,201.8125,202.875,203.875,204.9375,205.875,206.6875,207.6875,208.5625,209.5625,210.375,211.25,212.1875,213.1875,214.25,215.125,216,216.8125,217.8125,218.6875,219.6875,220.6875,221.6875,222.6875,223.5625,224.5625,225.5625,226.5625,227.625,228.6875,229.75,230.8125,231.875,232.9375,233.9375,234.9375,235.9375,236.9375,237.875,238.8125,239.6875,240.5,241.375,242.3125,243.1875,244.1875,245.1875,246.1875,247.125,248.125,249.0625,249.9375,250.875,251.875,252.875,253.75,254.75,255.75,256.75,257.5625,258.4375,259.3125,260.125,261,261.875,262.6875,263.5625,264.5,265.375,266.375,267.1875,268.0625,268.9375,269.9375,270.9375,271.9375,272.8125,273.8125,274.8125,275.8125,276.8125,277.875,278.875,280.1875,281.5625,282.875,286.5,289.4375,290.375,291.1875,292.0625,293.0625,294,295,296,297,298,299,300,301.0625,302.0625,302.9375,303.875,304.8125,305.625,306.5,307.375,308.25,309.125,310.125,311.125,312.0625,313.0625,314.0625,315.0625,316.125,317.1875,318.1875,319.125,320.125,321.125,322.0625,323.0625,324.0625,325,326.25,330.9375,334.0625,335.0625,336.0625,336.9375,337.9375,338.9375,340,340.9375,341.875,342.9375,343.9375,345,346,347.0625,348.0625,349.125,350.375,351.375,352.375,353.3125,354.375,355.4375,356.5,359.5625],"SensorReading_Radii":[471,468,642,661,665,668,671,676,679,686,694,698,704,706,718,723,731,737,748,762,755,734,719,699,682,669,652,647,606,590,578,574,561,349,333,294,347,359,366,378,446,460,449,438,440,405,402,412,414,402,406,407,412,412,407,407,404,425,403,387,386,396,400,399,399,400,405,404,386,284,261,261,275,411,410,411,400,409,407,416,406,410,412,422,419,439,444,434,429,440,457,459,463,468,471,480,481,488,490,495,500,509,514,523,139,543,552,562,573,567,555,551,148,164,164,167,273,244,388,426,409,355,425,266,289,286,281,278,278,273,288,304,324,351,381,379,508,514,512,510,512,516,560,602,601,600,566,529,520,598,194,180,161,161,167,158,110,106,114,161,155,155,145,131,139,153,161,173,145,117,115,120,124,167,148,147,171,163,195,205,212,213,215,219,221,225,228,183,170,169,156,152,240,252,256,260,256,261,260,260,261,266,267,269,270,277,278,268,267,268,264,267,269,270,274,288,285,282,280,281,279,276,276,274,273,275,271,270,269,255,252,259,268,268,265,265,265,266,266,267,267,266,267,267,268,267,204,178,155,140,130,128,137,128,131,134,138,134,140,142,279,305,307,311,313,314,316,324,326,282,274,275,310,344,342,341,340,340,339,338,336,337,336,330,322,277,259,263,323,330,325,322,316,313,309,307,300,300,293,630,641,633,635,631,630,632,637,641,641,638,636,632,629,631,620,597,606,616,622,625,631,632,614,459],"SensorReading_SignalStrength":[159,70,112,191,191,191,191,191,191,191,191,191,191,191,191,199,191,191,191,183,183,183,191,183,191,191,191,191,112,191,191,199,183,112,191,183,191,183,191,191,167,175,191,199,191,167,191,191,191,191,191,191,183,183,191,191,191,199,191,191,191,199,199,191,191,191,199,191,199,167,199,199,199,199,199,183,159,98,191,167,199,175,84,175,126,191,199,199,199,191,191,191,191,191,199,191,191,199,191,199,191,191,191,183,167,191,191,191,199,167,167,183,65,199,199,199,183,199,167,167,191,199,183,98,199,191,191,191,199,191,191,199,199,191,191,191,126,191,191,191,199,175,183,199,199,191,191,183,191,159,112,199,199,199,191,199,191,199,199,199,199,199,199,191,191,191,199,199,183,199,199,199,199,191,183,183,191,183,199,199,199,199,199,199,199,199,191,183,199,199,199,199,191,199,199,191,191,191,191,191,191,191,183,183,183,183,191,199,191,183,191,191,199,199,199,199,199,199,199,191,199,199,199,199,199,199,199,199,199,191,199,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,191,191,199,191,183,191,191,191,191,175,159,159,84,91,199,199,199,191,199,199,191,191,191,199,191,191,199,199,199,199,199,199,199,199,199,191,199,191,191,199,199,191,199,191,191,191,199,199,199,199,191,199,65,98,191,191,199,199,191,191,199,191,159,191,199,175,191,191,183,167,191,191,191,191,191,191,98]},{"TimeStamp":1496454231256,"SensorReading_Angles":[3.625,4.75,5.8125,6.8125,7.8125,8.875,9.8125,10.8125,11.875,12.875,13.875,14.8125,15.8125,16.875,17.9375,19,20,21.0625,22.3125,23.3125,24.3125,25.3125,26.375,27.4375,28.5,32.0625,33,34,35.0625,36.125,37.1875,38.25,39.3125,40.375,42.8125,43.8125,44.75,45.6875,46.75,47.8125,48.75,49.75,52.5,53.4375,54.5,55.5,56.4375,57.375,58.375,59.375,60.4375,61.4375,62.5,63.5625,64.625,65.625,66.625,67.5625,68.375,69.375,70.4375,71.5,72.375,73.375,74.375,75.375,76.25,77.25,78.25,79.25,80.4375,81.25,82.125,83.1875,84.0625,84.9375,86.125,87.3125,90.1875,91.1875,92.4375,93.4375,94.4375,95.625,98.9375,99.9375,100.875,101.875,102.875,103.9375,105,105.875,106.9375,107.9375,108.9375,110,111,112,112.875,113.75,114.75,115.75,116.6875,117.625,118.625,119.625,120.625,121.5,123.1875,126.0625,127.0625,128,129,129.9375,130.9375,131.9375,132.75,133.75,134.75,135.6875,136.5,137.375,138.25,139.0625,139.9375,140.9375,141.9375,142.8125,143.75,148.6875,151.625,152.6875,153.6875,154.5625,155.9375,156.9375,158.1875,159.3125,161.5625,162.625,163.625,164.6875,165.75,166.8125,167.875,168.9375,170,171.0625,172.125,173.1875,174.5,178.125,179,179.8125,180.8125,181.8125,182.8125,183.75,184.5625,185.4375,186.25,187.125,187.9375,188.8125,189.625,190.625,191.5625,192.5625,193.625,194.4375,195.3125,196.125,197,197.8125,198.6875,199.5,200.3125,201.1875,202,202.875,203.6875,204.5,205.375,206.1875,207.0625,207.875,208.75,209.5625,210.375,211.375,212.375,213.1875,214.1875,215.125,216.125,217.125,218,219,220.1875,221.1875,222.1875,223.375,224.25,225.25,226.1875,227.1875,228.1875,229.1875,230.125,230.9375,231.9375,233,234.0625,235.125,236.0625,237.0625,238.0625,239.0625,240,241,242,243,244,244.9375,245.9375,246.9375,247.9375,249,249.8125,250.8125,251.8125,252.6875,253.5625,254.375,255.25,256.125,256.9375,257.8125,258.6875,259.5,260.375,261.375,262.375,263.375,264.1875,265.125,266,267,268,269.0625,270.125,271.0625,272.0625,273,274,275,276,277,278.0625,279.125,280.375,281.75,285.4375,286.375,287.3125,288.3125,289.125,290,290.8125,291.6875,292.5625,293.625,294.5,295.375,296.375,297.375,298.1875,299.1875,300.1875,301.1875,302.1875,303.25,304.3125,305.375,306.4375,307.5,308.625,309.6875,310.5,311.375,312.25,313.1875,314.1875,315.125,316.125,317.125,318.125,319.0625,320,320.875,321.6875,322.6875,323.5625,324.6875,329.625,330.75,333.875,334.8125,335.8125,336.75,337.625,338.5625,339.625,340.6875,343.1875,344.375,345.375,346.375,347.5625,348.75,349.75,350.8125,351.6875,352.6875,353.6875,354.75,356.25,357.5,358.8125],"SensorReading_Radii":[488,589,640,651,656,659,663,667,674,675,680,688,693,699,704,712,719,724,734,743,750,749,728,715,690,597,577,566,571,590,581,569,536,541,344,334,332,336,346,352,365,372,418,441,433,419,397,396,407,397,398,397,405,412,401,405,403,414,423,396,391,392,393,393,393,395,398,407,403,378,318,259,260,262,401,413,411,412,411,409,420,416,409,415,430,417,415,419,439,450,435,431,451,462,467,472,476,479,483,488,491,496,503,508,513,523,530,536,149,139,147,145,146,143,148,139,145,148,153,156,160,170,174,171,170,173,179,188,198,245,309,309,287,350,388,331,1125,392,523,519,519,516,518,522,544,552,547,523,527,519,533,225,178,164,171,163,126,115,114,116,115,116,118,120,119,118,117,116,119,121,122,121,123,124,125,125,127,128,129,129,130,131,133,134,137,138,138,139,143,145,146,148,149,155,206,254,260,264,269,275,279,289,292,299,296,296,299,312,311,302,273,270,269,269,271,273,273,290,290,286,281,279,278,279,278,276,276,273,272,273,267,270,269,268,268,268,268,267,268,262,259,260,263,266,264,266,266,235,182,156,132,128,130,133,128,132,131,131,133,132,135,139,163,295,297,303,303,307,307,311,315,317,320,320,327,289,270,270,273,281,293,295,294,294,296,300,295,283,261,255,255,261,329,329,326,322,315,311,308,306,302,302,296,295,611,624,628,630,628,627,628,638,639,637,636,632,626,628,594,589,607,609,627,617,631,630,569,450,446],"SensorReading_SignalStrength":[70,183,183,191,191,191,191,191,191,191,191,183,191,191,191,191,199,191,191,183,191,191,191,183,183,84,191,191,191,191,199,191,183,175,126,199,183,191,191,191,191,191,112,191,199,191,199,191,191,191,191,199,191,191,175,191,191,199,199,191,191,191,199,191,191,199,191,199,199,199,199,199,199,199,175,199,191,159,98,199,159,183,191,183,98,191,199,191,191,191,191,199,191,191,191,191,199,191,199,199,191,199,199,191,191,199,199,199,183,98,199,191,199,199,191,191,191,199,191,199,191,199,199,199,199,199,199,199,199,45,98,199,199,183,191,191,175,191,126,191,191,191,183,183,191,191,183,191,183,183,183,84,199,199,199,191,175,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,199,191,199,191,191,191,191,191,183,191,191,191,199,199,199,199,191,191,191,191,191,199,199,199,199,199,199,199,199,199,199,199,199,199,191,199,199,199,199,199,199,199,199,199,199,199,191,199,199,199,199,199,199,175,191,183,199,191,191,183,183,191,183,191,191,159,159,84,199,199,191,199,199,199,199,199,199,199,199,199,199,199,199,199,191,191,191,191,191,191,191,191,191,199,199,199,199,191,191,191,191,191,191,199,199,199,191,199,191,40,167,98,191,199,199,199,191,191,183,126,175,199,191,183,175,183,199,199,191,191,191,167,183,159]},{"TimeStamp":1496454231781,"SensorReading_Angles":[2.8125,4,5,5.9375,6.9375,7.9375,9,10,10.9375,11.9375,12.9375,14,15,15.9375,17,17.9375,18.9375,19.9375,21,22.125,23.125,24.1875,25.25,26.3125,27.375,30.6875,31.6875,32.75,33.8125,34.875,35.9375,36.9375,38,39.0625,41.5625,42.625,43.5625,44.625,45.5625,46.5625,47.5625,48.75,49.75,50.6875,51.6875,52.6875,53.6875,54.6875,55.625,56.6875,57.75,58.8125,59.875,60.9375,62,63.0625,64,65.0625,66.0625,67,68,68.875,69.75,70.6875,71.625,72.5,73.625,74.5625,75.5625,76.5,77.3125,78.3125,79.5625,80.4375,81.25,82.125,83.125,84.0625,85.4375,88.375,89.375,90.375,91.375,92.5,93.4375,94.25,95.625,96.875,99.0625,100.1875,101.1875,102.1875,103.1875,104.1875,105.125,106.125,107.125,108,108.875,109.6875,110.5625,111.5625,112.625,113.5,114.5,115.5,116.5,117.5,118.5,119.4375,121.8125,122.8125,123.875,125.125,126.25,127.5,130.5,131.5,132.4375,133.25,134.125,134.9375,135.8125,136.6875,137.5,138.375,139.25,140.0625,140.9375,143.75,148.625,149.625,150.5,151.5,152.5625,154,155,156.625,158,159,159.9375,161,162.0625,163.125,164.1875,165.5,166.5,167.4375,168.4375,169.4375,170.5,171.5625,173.1875,176.3125,180.8125,181.6875,182.5625,183.375,184.25,185.0625,185.9375,186.75,187.625,188.4375,189.25,190.125,190.9375,191.8125,192.625,193.5,194.3125,195.1875,196,196.8125,197.6875,198.5625,199.5625,200.5625,201.5,202.5,203.5625,204.625,205.5,206.5,207.4375,208.4375,209.4375,210.3125,211.1875,212,213,213.9375,214.8125,215.625,216.5,217.4375,218.4375,219.5,220.625,221.5625,222.5,223.5,224.5,225.5625,226.625,227.6875,228.75,229.6875,230.6875,231.6875,232.75,233.8125,234.6875,235.5625,236.5625,237.5625,238.5625,239.4375,240.4375,241.4375,242.3125,243.125,244,245,246,247,248,248.9375,249.75,250.625,251.625,252.5,253.3125,254.1875,255.0625,255.875,256.75,257.5625,258.4375,259.3125,260.125,261.125,262,262.875,263.6875,264.625,265.625,266.625,267.6875,268.625,269.625,270.625,271.625,272.625,273.6875,275,276.1875,277.375,278.625,282.4375,285.1875,286.125,287.1875,288.125,289,290,291,292,293.0625,293.875,294.75,295.75,296.8125,297.875,298.75,299.625,300.5,301.3125,302.1875,303.1875,304.0625,305.0625,306.0625,307.0625,308.1875,309.1875,310.25,311.125,311.9375,312.9375,313.8125,314.75,315.75,316.75,317.75,318.6875,319.625,320.5625,321.5625,322.6875,327.625,329,331.6875,332.625,333.625,334.625,335.5625,336.5625,337.5,338.5,339.5,340.5,341.5625,342.625,343.6875,344.75,345.8125,346.8125,347.8125,348.8125,349.8125,350.875,351.9375,353,356.3125],"SensorReading_Radii":[499,612,636,646,654,657,662,666,672,675,683,685,689,694,704,714,720,726,732,737,748,748,726,707,688,595,577,564,571,592,583,570,544,545,350,338,336,336,345,354,361,378,438,445,445,436,448,398,402,415,409,412,421,409,415,419,414,407,408,427,415,407,407,403,402,402,401,402,411,415,407,407,281,261,262,271,414,416,417,415,416,422,415,409,419,420,425,425,424,420,437,450,439,438,455,462,466,470,476,480,481,486,490,499,505,511,516,524,534,540,567,565,573,574,564,554,153,161,160,162,164,168,178,175,175,177,178,183,189,222,276,312,310,287,360,386,334,1125,1124,522,522,520,521,517,518,522,528,526,532,524,520,523,534,214,125,114,113,114,114,115,115,116,116,116,117,118,116,116,117,119,119,121,123,123,124,125,128,131,142,145,155,168,183,194,210,213,226,178,176,152,159,249,253,257,261,266,258,260,263,262,263,264,267,269,271,276,283,269,266,267,267,265,268,269,282,287,284,281,279,279,274,273,271,273,271,270,270,269,268,256,253,266,266,265,266,265,265,265,265,263,263,263,265,265,265,261,195,165,140,125,129,125,131,124,127,132,135,133,132,136,276,299,302,305,306,309,313,318,317,271,270,274,312,333,342,338,338,336,337,334,333,334,333,332,331,326,271,254,261,322,325,321,318,312,310,306,303,299,297,294,614,621,626,630,628,624,632,638,636,637,634,630,634,632,629,610,591,606,610,614,627,628,629,620,466],"SensorReading_SignalStrength":[70,183,183,183,199,191,191,191,191,191,191,183,191,191,199,191,191,199,191,199,175,191,183,183,191,98,183,191,191,199,199,191,191,191,112,191,191,183,199,183,191,183,175,183,191,199,191,167,191,191,191,191,191,191,191,199,183,191,191,199,199,199,199,199,199,191,191,191,199,199,199,199,159,199,199,199,191,199,167,98,183,191,183,191,199,199,183,191,126,191,199,199,191,199,199,199,199,199,191,199,199,199,199,199,199,191,191,191,191,191,175,199,191,167,167,175,98,183,199,199,191,199,199,199,199,199,199,199,199,199,70,191,199,199,191,191,191,167,159,191,183,191,191,191,191,175,183,191,191,191,191,191,175,98,70,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,191,191,191,191,191,191,191,199,199,199,191,199,199,199,183,199,199,199,191,191,191,191,199,183,191,183,199,191,183,183,191,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,191,191,191,191,191,191,191,183,167,175,183,159,84,112,199,199,199,199,191,199,199,199,199,199,199,191,191,199,199,199,199,199,199,199,199,191,199,199,199,191,199,199,191,199,191,191,191,191,199,191,199,199,191,40,159,98,199,199,199,199,191,191,191,183,191,183,175,191,183,191,183,191,191,191,191,191,191,98]},{"TimeStamp":1496454232284,"SensorReading_Angles":[0.625,1.8125,2.8125,3.75,4.75,5.75,6.75,7.75,8.75,9.8125,10.875,11.9375,13,14.0625,15.125,16.1875,17.25,18.3125,19.375,20.4375,21.4375,22.6875,23.75,24.75,25.8125,26.875,27.9375,31.375,32.375,33.375,34.4375,35.4375,36.375,39.25,40.1875,41.125,42.125,43.125,44.1875,45.125,46.125,47.125,48.0625,49,50.0625,51.125,52.1875,53.25,55.5625,56.5625,57.5625,58.5625,59.5625,60.625,61.6875,62.75,63.75,64.6875,65.625,66.625,67.625,68.625,69.6875,70.5625,71.5625,72.5625,73.5,74.4375,75.3125,76.25,77.5,78.4375,79.4375,80.375,81.3125,82.5625,85.125,86.125,87.0625,88.125,89.125,90.0625,91.0625,92.25,93.25,96,97,98,98.9375,99.9375,100.9375,101.9375,102.875,103.875,104.875,105.75,106.625,107.625,108.625,109.5625,110.4375,111.4375,112.375,113.3125,114.3125,115.375,116.3125,119.75,120.75,121.9375,123.125,124.25,127.6875,128.6875,129.625,130.5625,131.4375,132.1875,133.0625,134,134.9375,135.875,136.75,137.625,139.5,144.4375,145.625,146.625,147.6875,148.6875,149.6875,151,152.0625,153.875,155.5625,156.5625,157.5625,158.5625,159.5625,160.625,161.6875,162.75,163.8125,164.875,165.9375,166.875,167.875,169.125,173.25,177.9375,178.9375,179.875,180.875,181.8125,182.625,183.4375,184.3125,185.125,186,186.8125,187.6875,188.5,189.375,190.3125,191.3125,192.1875,193.0625,193.875,194.75,195.5625,196.4375,197.25,198.1875,199.125,200.125,201.125,202.0625,203.125,204.125,205.0625,206.0625,207,207.8125,208.625,209.625,210.625,211.5625,212.5,213.5,214.5,215.4375,216.4375,217.375,218.375,219.4375,220.5,221.5625,222.625,223.6875,224.75,225.6875,226.75,227.8125,228.875,229.9375,231,232.0625,233,233.875,234.875,235.875,236.9375,237.8125,238.8125,239.8125,240.75,241.75,242.5625,243.4375,244.3125,245.125,246,246.875,247.6875,248.5625,249.4375,250.375,251.375,252.375,253.375,254.375,255.3125,256.1875,257,257.875,258.75,259.5625,260.4375,261.3125,262.125,263.125,264.125,265.125,266.125,267.1875,268.25,269.375,270.3125,271.4375,272.5,273.8125,275.125,276.25,277.5625,278.75,282.8125,283.6875,284.6875,285.6875,286.5,287.375,288.375,289.1875,290.1875,291.1875,292.1875,293.125,293.9375,294.9375,296,297.0625,298.0625,299.0625,300.0625,301.0625,302.0625,302.9375,303.9375,304.9375,305.9375,307,307.8125,308.6875,309.5625,310.5,311.5,312.4375,313.4375,314.4375,315.4375,316.3125,317.1875,318,319,320,321,325.8125,329,330,330.9375,331.9375,332.9375,333.875,334.8125,335.75,336.75,339.125,340.125,341.1875,342.25,343.3125,344.3125,345.3125,346.1875,347.1875,348.1875,349.25,350.25,351.1875,352.4375,355.875],"SensorReading_Radii":[490,607,645,650,657,661,668,669,674,680,686,690,700,703,708,720,723,737,739,753,749,730,712,692,675,661,644,608,596,584,573,564,554,387,337,336,342,349,358,380,460,484,478,474,454,454,462,455,442,419,411,414,411,408,404,407,428,419,403,407,403,401,400,400,399,412,420,418,417,409,295,277,396,418,421,422,411,421,423,414,417,419,418,429,429,428,426,447,453,440,437,453,468,467,474,477,479,485,486,497,499,506,512,518,524,532,543,567,580,577,564,559,154,162,159,162,163,178,177,177,177,180,187,192,223,256,316,315,309,283,376,377,338,387,515,521,517,519,516,514,516,523,523,530,527,524,520,520,208,119,113,113,113,114,113,115,116,115,116,116,116,117,117,118,119,118,120,123,124,123,125,134,143,156,160,171,186,198,212,219,224,228,178,173,155,157,248,253,259,263,263,256,262,260,265,265,265,269,271,269,271,280,268,266,267,266,266,269,271,287,285,283,282,279,278,277,273,268,269,269,269,269,269,267,263,253,264,266,265,265,265,264,265,265,265,265,261,263,265,266,242,187,157,140,128,129,130,129,127,133,134,132,136,135,139,205,296,300,303,305,308,312,314,317,323,304,269,267,272,312,341,340,337,336,337,335,333,332,331,328,310,266,256,257,290,329,325,322,318,316,308,306,302,300,298,299,623,635,631,634,633,626,631,635,642,636,633,631,631,631,626,615,625,609,611,628,625,634,633,559,451],"SensorReading_SignalStrength":[70,167,191,199,191,191,191,191,191,191,191,191,183,183,191,191,191,183,191,191,183,183,191,183,175,191,191,84,191,191,191,183,191,98,191,199,199,199,199,191,183,199,199,199,191,191,191,191,126,175,191,183,191,191,191,191,199,199,199,191,191,183,183,199,199,199,199,199,199,191,175,191,167,199,199,167,112,183,191,191,199,191,199,183,191,112,191,199,191,191,191,191,191,199,199,199,199,191,199,191,199,191,191,191,199,191,191,84,191,159,175,175,84,199,199,199,199,199,199,199,199,199,199,199,191,50,159,199,199,191,191,191,191,159,159,191,191,199,183,191,183,175,183,191,191,191,191,183,167,70,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,191,191,191,191,191,191,191,199,199,199,199,199,183,199,191,191,199,191,199,191,191,191,183,183,191,183,191,183,199,191,183,183,191,199,199,199,199,199,191,199,199,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,175,191,199,191,183,191,183,191,183,167,167,159,167,183,70,199,199,199,199,199,199,199,199,199,191,199,199,199,191,191,199,199,199,199,199,199,199,199,191,199,199,199,199,199,191,191,191,191,199,199,199,199,199,199,199,45,98,191,191,191,199,199,199,199,191,126,191,175,191,191,191,191,199,191,191,199,191,191,167,84]},{"TimeStamp":1496454232800,"SensorReading_Angles":[0.1875,1.25,2.3125,3.25,4.3125,5.25,6.25,7.1875,8.125,9.125,10.125,11.1875,12.25,13.3125,14.375,15.3125,16.375,17.4375,18.5,19.5625,20.625,21.625,22.875,23.875,24.9375,26,27.0625,29.875,30.8125,31.75,32.75,33.75,34.6875,35.75,37.1875,39.5625,40.5625,41.5,42.3125,43.3125,44.5,45.5,46.4375,47.25,48.25,49.3125,50.375,51.375,52.875,54,55,56.0625,57.125,58.1875,59.25,60.3125,61.375,62.25,63.125,63.9375,64.9375,65.75,66.6875,67.6875,68.6875,69.6875,70.625,71.5625,72.375,73.25,74.0625,74.9375,75.9375,78.6875,79.5,80.5625,81.875,82.875,84.25,85.25,86.5625,87.625,88.6875,89.6875,90.75,91.8125,94.6875,95.6875,96.8125,97.75,98.75,99.75,100.6875,101.6875,102.6875,103.6875,104.5625,105.375,106.25,107.125,108,109,110.0625,111.0625,112.125,113.125,114.125,115.0625,118.5,119.4375,120.8125,122,123.1875,126.4375,127.3125,128.1875,129,130,131.0625,131.9375,132.75,133.625,134.5,135.3125,136.1875,137.1875,142.0625,145.1875,146.1875,147.1875,148.25,149.25,150.3125,154.9375,155.9375,156.9375,157.9375,159,160,161.3125,162.5,163.5,164.5625,165.625,166.6875,167.9375,172.875,176.6875,177.5,178.375,179.1875,180.0625,180.875,181.6875,182.5625,183.375,184.25,185.0625,185.9375,186.75,187.625,188.4375,189.25,190.125,190.9375,191.8125,192.75,193.8125,194.75,195.75,196.6875,197.625,198.4375,199.4375,200.3125,201.1875,202,203,203.875,204.875,205.875,206.6875,207.5625,208.5,209.5,210.5,211.4375,212.5,213.5,214.5,215.4375,216.4375,217.375,218.375,219.375,220.5625,221.5625,222.625,223.6875,224.75,225.8125,226.75,227.8125,228.8125,229.875,230.8125,231.6875,232.5,233.5,234.5,235.5625,236.5625,237.625,238.5625,239.5,240.5,241.375,242.25,243.0625,243.9375,244.8125,245.625,246.5,247.5,248.4375,249.4375,250.25,251.125,252,252.8125,253.6875,254.5625,255.375,256.25,257.125,257.9375,258.8125,259.6875,260.5,261.375,262.375,263.375,264.1875,265.1875,266.25,267.375,268.4375,269.5,270.5625,271.8125,273.0625,274.4375,275.75,277,278.125,282.0625,283.0625,284,285,286,287,288,289,289.9375,290.9375,291.875,292.875,293.875,294.9375,295.9375,296.875,297.875,298.875,299.75,300.75,301.75,302.75,303.75,304.8125,305.6875,306.5625,307.4375,308.3125,309.3125,310.3125,311.3125,312.25,313.0625,314.0625,315.0625,316.0625,316.9375,317.9375,318.9375,323.8125,326.25,327.1875,328.25,329.3125,330.1875,331.1875,332.1875,333.25,334.125,335.1875,336.4375,337.4375,338.4375,339.625,340.625,341.625,342.625,343.625,344.5,345.5,346.5,347.5,348.5625,349.625,350.625,354.0625,358.8125,359.75],"SensorReading_Radii":[546,649,654,657,661,665,671,673,677,684,691,692,696,706,714,720,728,738,748,754,738,724,704,687,671,657,639,616,600,589,578,567,564,554,514,349,342,352,358,373,443,487,483,482,476,449,464,461,463,449,418,418,414,411,411,405,405,418,429,412,404,409,418,413,416,411,405,416,415,418,419,415,397,384,416,414,416,406,418,417,418,413,418,415,425,420,432,425,447,453,445,438,452,467,467,473,474,477,482,489,495,497,504,509,515,524,531,540,570,577,578,557,556,153,163,159,161,162,176,178,176,177,180,184,189,199,255,310,310,291,351,393,334,1138,523,516,519,515,516,520,523,526,522,521,522,549,1108,115,109,113,114,114,115,114,114,115,116,116,117,117,119,120,124,123,125,131,141,146,135,160,184,191,193,209,213,217,214,222,223,228,231,178,174,154,154,250,252,255,262,265,256,260,258,264,265,266,270,273,270,270,278,265,265,264,264,268,270,272,287,284,283,282,281,280,275,274,273,269,269,269,269,269,268,256,252,265,266,266,266,264,265,263,264,264,266,266,265,264,265,266,203,170,149,134,126,128,132,131,129,132,134,130,134,134,132,246,299,302,305,309,311,313,320,323,309,271,271,273,310,333,334,334,332,329,326,323,321,314,292,260,257,257,265,327,329,324,319,318,312,309,305,303,300,298,671,665,658,651,651,647,643,641,639,640,637,637,634,635,633,633,629,631,629,612,608,628,618,631,629,549,450,583,650],"SensorReading_SignalStrength":[70,183,191,191,199,199,199,191,191,191,183,183,191,191,199,191,183,191,191,191,191,191,183,183,191,191,191,98,191,199,191,191,191,191,159,126,199,191,199,191,183,191,199,191,199,191,191,199,191,167,191,183,175,183,191,191,199,199,199,199,191,191,191,199,199,199,199,199,199,199,199,199,191,98,199,191,159,191,159,175,175,191,175,199,199,183,98,191,199,199,199,191,199,191,199,199,199,199,199,199,191,191,191,191,191,199,191,191,84,191,167,167,183,84,199,199,199,199,199,199,199,199,199,199,199,199,55,98,199,199,183,199,167,65,191,191,191,199,191,175,175,183,175,183,183,175,40,84,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,191,191,191,191,199,191,199,191,199,199,199,191,199,191,199,199,199,191,199,199,199,191,199,199,191,191,191,199,183,183,191,191,191,199,191,191,191,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,199,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,183,191,191,183,191,183,191,191,183,175,175,167,159,159,159,78,199,199,199,199,199,191,191,199,199,199,199,199,191,191,199,191,191,191,199,199,191,191,191,199,199,199,199,183,191,191,199,191,199,199,199,191,199,199,55,112,191,191,191,191,191,191,191,191,191,159,191,191,159,191,199,191,191,191,191,191,199,191,191,183,84,55,199]},{"TimeStamp":1496454233313,"SensorReading_Angles":[0.75,1.75,2.6875,3.75,4.8125,5.8125,6.875,7.875,8.875,9.8125,10.8125,11.875,12.875,13.875,14.9375,15.875,16.9375,18,19,20.0625,21.125,22.25,23.25,24.1875,25.1875,26.1875,27.25,28.3125,29.1875,30.1875,31.1875,32.1875,33.1875,34.0625,35.0625,36.625,37.625,38.5625,39.5625,40.5625,41.5625,42.5625,43.5625,44.5625,45.5625,46.4375,47.375,48.3125,49.3125,50.3125,51.375,52.375,53.4375,54.4375,55.4375,56.4375,57.375,58.4375,59.4375,60.375,61.1875,62.0625,62.875,63.75,64.625,65.4375,66.3125,67.25,68.25,69.25,70.125,71,71.8125,72.6875,73.5,74.5,75.5,76.4375,77.25,78.25,79.4375,82.3125,83.6875,85.0625,86.25,87.125,87.875,89.125,90.125,93.4375,94.25,95.125,96.125,97.125,98.125,99.1875,100.0625,100.9375,101.8125,102.6875,103.5625,104.375,105.25,106.125,107,108,109,110.0625,111.125,112.125,113.1875,116.5,117.5,118.6875,119.8125,121.125,124.5625,125.5625,126.5625,127.5,128.375,129.25,130.0625,130.9375,131.75,132.5625,133.375,134.25,139.0625,142.3125,143.3125,144.25,145.3125,146.3125,149.9375,152.6875,153.6875,154.625,155.6875,156.625,157.8125,159,160,161.0625,162.125,163.1875,164.5,169.375,170.4375,173.4375,174.25,175.125,175.9375,176.8125,177.75,178.5625,179.375,180.25,181.0625,181.9375,182.75,183.625,184.5625,185.4375,186.25,187.125,187.9375,188.8125,189.625,190.4375,191.3125,192.125,193,193.8125,194.6875,195.5,196.375,197.1875,198.125,198.9375,199.9375,200.875,201.9375,202.8125,203.625,204.625,205.5625,206.5625,207.4375,208.3125,209.3125,210.25,211.25,212.3125,213.3125,214.375,215.4375,216.5,217.5,218.5625,219.8125,220.8125,221.6875,222.6875,223.6875,224.625,225.5,226.375,227.1875,228.1875,229.1875,230.25,231.25,232.25,233.125,234.125,235.125,236.125,237.125,238.0625,238.875,239.75,240.5625,241.4375,242.375,243.1875,244.0625,244.9375,245.75,246.625,247.5,248.3125,249.1875,250.0625,250.875,251.75,252.625,253.4375,254.4375,255.3125,256.3125,257.3125,258.3125,259.375,260.4375,261.5,262.5625,263.625,264.5,265.5625,266.875,268.0625,269.4375,270.75,274.625,275.625,276.625,277.5,278.3125,279.1875,280.1875,281.1875,282.1875,283.125,284.125,285.125,286.25,287.25,288.3125,289.375,290.4375,291.4375,292.5,293.5625,294.625,295.6875,296.75,297.625,298.5,299.3125,300.1875,301.0625,302.0625,303,304,304.9375,305.9375,306.9375,308,308.8125,309.8125,310.8125,311.8125,313.375,318.25,319.4375,320.4375,321.5,322.5625,323.4375,324.375,325.4375,326.4375,327.5,328.5,329.5625,330.4375,331.75,332.75,333.6875,334.6875,335.6875,336.6875,337.75,338.8125,339.875,340.9375,342,343,344.3125,345.5,350.375,351.375,352.25,353.25,354.25,355.3125,356.3125,357.1875,358.1875,359.1875],"SensorReading_Radii":[653,661,660,663,673,673,680,685,691,695,702,707,718,724,730,738,751,759,746,723,705,691,673,659,643,631,620,609,599,588,576,567,558,553,543,414,339,344,347,354,360,369,465,484,481,474,463,466,462,461,456,443,420,412,411,411,411,405,406,420,429,412,410,409,426,421,422,420,420,419,418,416,416,416,415,412,409,416,417,418,416,417,423,425,423,419,417,426,425,437,447,453,453,436,443,463,466,468,470,477,482,483,486,491,499,506,510,517,522,531,542,570,578,573,562,546,145,159,159,161,171,177,175,174,177,182,185,191,248,310,309,297,321,387,351,520,519,516,514,515,519,520,519,526,520,523,538,197,161,125,108,107,108,111,111,113,114,115,115,116,115,116,118,119,119,120,119,121,122,121,122,122,124,126,129,130,132,137,143,149,161,164,198,172,175,154,161,252,255,258,260,260,260,264,266,263,265,268,271,273,277,284,271,269,268,267,267,268,271,283,288,285,284,281,281,279,278,276,275,271,271,271,271,269,250,250,265,268,267,266,267,266,265,267,268,266,266,266,266,267,259,192,168,143,125,129,125,131,133,133,133,132,137,138,143,295,296,300,304,308,312,313,317,324,326,294,272,272,289,318,328,324,317,302,299,294,283,270,263,258,261,265,285,333,331,326,320,316,313,309,308,302,298,298,646,660,657,653,650,649,644,646,643,639,639,633,633,639,634,633,634,633,627,615,625,624,631,633,557,464,445,568,648,655,658,658,662,668,674,674,682],"SensorReading_SignalStrength":[199,191,191,191,183,191,191,191,191,183,191,191,191,199,191,183,191,183,183,191,199,191,199,191,183,191,191,183,191,191,191,191,191,191,199,191,191,191,191,199,191,199,183,199,199,199,191,191,199,199,191,191,191,191,191,183,191,191,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,191,199,199,199,167,98,159,159,175,199,199,175,199,98,191,191,191,199,199,191,199,199,199,199,191,199,199,199,199,191,199,191,199,191,191,98,199,167,159,167,84,199,199,199,199,199,199,199,199,199,199,199,55,98,199,199,191,191,84,112,191,199,191,199,183,183,183,183,183,183,175,60,191,98,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,199,191,199,199,199,199,199,199,199,191,191,199,191,191,183,191,191,191,183,191,175,199,199,191,191,199,199,199,199,199,199,191,191,199,199,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,191,191,191,191,183,183,191,183,167,159,159,159,70,191,199,199,199,199,191,199,191,199,199,199,199,191,191,191,191,191,191,191,191,191,191,199,199,199,199,199,199,199,199,191,199,199,199,199,191,199,199,199,45,175,191,191,191,199,191,191,191,191,191,191,199,191,191,191,191,191,183,199,191,191,191,191,175,159,159,50,191,199,199,191,191,191,191,199,183]},{"TimeStamp":1496454233826,"SensorReading_Angles":[0.125,1.125,2.125,3.375,4.875,7.625,8.625,9.625,10.6875,11.75,12.8125,13.875,14.9375,15.875,16.9375,18,19.0625,20.125,21.0625,22.5,23.5,24.5,25.4375,26.375,27.75,28.75,29.625,30.5,31.3125,32.5,33.375,34.3125,35.25,36.1875,37.0625,37.875,38.875,39.9375,40.9375,41.8125,42.8125,43.8125,44.625,45.6875,46.6875,47.625,48.4375,49.3125,50.125,51,51.8125,52.6875,53.5,54.375,55.25,56.0625,56.9375,57.75,58.625,59.4375,60.4375,61.4375,62.4375,63.4375,64.3125,65.1875,65.75,66.5625,67.4375,68.25,69.125,69.9375,70.8125,71.625,72.5,73.3125,74.1875,75,75.875,76.6875,77.5625,78.375,79.25,80.0625,81.0625,82.0625,83,84,85.0625,86.125,87.0625,88.3125,89.25,90.125,91.125,92.125,93.0625,93.9375,94.9375,95.875,96.875,97.875,98.875,99.9375,100.9375,101.875,102.875,103.9375,104.875,106.5,107.3125,108.1875,109.0625,110,111,112,112.875,113.75,114.5625,115.4375,116.4375,117.4375,118.4375,119.375,120.375,121.3125,122.125,123,123.875,124.6875,125.6875,126.75,127.75,128.8125,129.875,130.9375,132.0625,133.75,137.625,139.3125,140.3125,141.3125,142.1875,143.1875,144.1875,145.25,146.25,147.3125,148.375,149.4375,150.5,151.625,152.875,156.125,157,157.8125,158.6875,159.6875,160.875,161.75,162.5625,163.5625,164.5625,165.5625,166.5,167.4375,168.4375,169.4375,170.4375,171.5,172.4375,173.4375,174.3125,175.375,176.375,177.4375,178.4375,179.5,180.5,181.5625,182.625,183.625,184.6875,185.6875,186.75,187.8125,188.6875,189.5625,190.375,191.25,192.0625,192.9375,193.875,194.875,195.875,196.8125,198.25,199.3125,200.25,201.3125,202.375,203.4375,204.4375,205.5,206.5625,207.625,208.625,209.5625,210.5625,211.5,212.5625,213.5,214.4375,215.4375,216.3125,217.1875,218.1875,219.125,219.9375,220.875,221.8125,222.8125,223.8125,224.625,225.5,226.375,227.1875,228.0625,228.875,229.75,230.625,231.4375,232.3125,233.125,234,234.875,235.6875,236.5625,237.5625,238.375,239.25,240.125,240.9375,241.8125,242.5,243.5625,244.6875,245.6875,246.6875,248,249.125,250.375,251.625,252.9375,256.4375,260.4375,263.5,264.5,265.375,266.1875,267.1875,268.1875,269.125,270.125,271.0625,272.0625,273.0625,274.0625,275,275.8125,276.6875,277.5625,278.375,279.25,280.125,281.125,282.0625,282.875,283.75,284.75,285.8125,286.875,287.75,288.6875,289.6875,290.6875,291.75,292.75,293.6875,294.5,295.5,296.5625,297.5,298.5,303.375,306.6875,307.6875,308.6875,309.6875,310.6875,311.6875,312.75,313.6875,315.0625,316.0625,317.25,318.25,319.25,320.1875,321.25,322.3125,323.25,324.25,325.25,326.25,327.1875,328.25,329.5625,330.6875,335.5625,336.5625,337.625,338.625,339.6875,340.6875,341.6875,342.75,343.75,344.75,345.6875,346.75,347.8125,348.875,349.9375,351,352,353,354,354.9375,356,357.0625,358.125,359.1875],"SensorReading_Radii":[687,700,705,719,732,748,763,769,742,722,707,688,669,653,638,626,612,598,588,581,570,558,550,544,395,350,359,367,373,467,496,492,484,480,474,473,469,467,461,459,454,451,448,447,442,436,438,434,433,431,429,427,426,420,422,423,422,420,419,418,417,415,418,416,416,417,416,418,417,417,418,415,417,420,419,424,425,427,427,429,432,432,435,436,438,443,449,450,453,451,458,462,465,472,476,480,486,490,497,502,506,513,518,527,535,544,549,563,572,154,166,164,161,157,154,148,146,146,150,151,156,159,162,169,171,177,182,190,195,205,224,348,372,377,381,381,324,1136,353,514,513,512,515,514,513,516,526,546,555,519,519,517,528,217,172,160,165,161,127,108,112,116,115,122,124,122,121,125,117,120,118,120,119,123,126,126,129,129,134,135,147,153,153,149,142,143,144,142,144,144,146,149,174,252,257,267,264,258,262,261,265,269,270,268,273,271,283,271,274,274,276,275,274,276,290,288,287,284,282,281,278,278,276,272,271,271,271,272,263,254,260,268,268,268,268,268,269,268,267,268,268,268,268,266,265,243,189,160,145,129,135,125,133,133,136,144,288,308,313,313,318,320,319,284,284,307,325,339,351,346,342,339,339,339,340,341,337,337,337,335,332,273,262,291,333,327,324,319,310,308,308,304,302,301,610,630,634,636,638,643,647,644,644,642,638,637,632,634,632,634,635,616,615,635,625,636,636,572,480,519,664,667,668,673,681,678,688,691,695,699,704,714,719,731,738,748,755,761,774,784,767,749,730],"SensorReading_SignalStrength":[191,183,183,175,159,98,183,191,175,183,183,191,191,191,191,183,191,191,191,191,191,191,191,191,183,199,199,199,199,183,199,199,199,199,199,199,199,191,199,199,191,191,191,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,199,199,199,199,199,199,191,191,199,199,199,199,199,199,199,199,191,191,199,191,191,191,191,199,191,191,183,183,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,183,191,191,191,191,175,191,84,175,191,191,191,191,191,183,183,191,183,191,191,191,191,84,199,199,199,199,175,199,199,191,191,199,199,191,199,191,191,191,191,191,199,199,191,191,191,191,191,191,191,183,183,183,183,191,199,199,199,199,199,199,199,199,199,191,183,191,191,191,191,191,183,191,191,183,191,199,199,199,199,199,191,191,199,199,199,191,199,199,199,199,199,199,199,199,199,199,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,183,191,191,175,167,167,167,159,84,70,91,199,199,199,191,199,199,191,199,183,183,191,191,199,199,199,199,199,199,199,199,199,199,199,199,191,199,191,199,199,191,199,199,199,199,199,199,199,45,98,191,199,191,199,191,191,183,167,183,183,159,191,199,191,191,191,199,199,191,191,191,183,167,60,175,191,191,191,183,191,183,191,191,191,191,191,183,183,191,183,191,183,183,191,183,175,183]},{"TimeStamp":1496454234351,"SensorReading_Angles":[0.375,1.4375,2.5,3.5,4.5625,5.625,6.6875,7.75,8.625,9.625,10.625,11.625,12.625,13.6875,14.6875,15.625,16.625,17.5625,18.5625,19.625,20.5625,21.5625,22.6875,23.5625,24.5625,25.4375,26.25,27.125,27.9375,28.8125,29.75,30.75,31.75,32.6875,33.625,34.625,35.625,36.6875,37.625,38.5625,39.5625,40.5,41.3125,42.1875,43,43.9375,45,45.875,46.6875,47.5625,48.375,49.25,50.0625,50.9375,51.9375,52.875,53.75,54.75,55.6875,56.6875,57.625,58.4375,59.3125,60.3125,61.125,62.125,63.125,64.125,65.0625,65.8125,66.75,67.75,68.75,69.75,70.625,71.5,72.3125,73.3125,74.1875,75.125,76.125,77.125,77.9375,78.9375,79.9375,80.9375,81.875,82.9375,84,84.9375,85.9375,86.875,88.0625,89.0625,90.125,91.125,92.125,93.125,94.0625,95.125,96.1875,97.3125,98.375,99.4375,100.5,101.625,102.6875,103.75,104.8125,106.125,107.125,108.125,109.1875,110.1875,111.1875,112.1875,113.1875,114.125,115.0625,116.0625,117.0625,118.0625,119.125,121.9375,122.9375,124.1875,125.75,126.75,127.8125,128.875,129.9375,131,131.9375,133.125,134.125,135.125,136.125,137.125,138.125,139.0625,140.125,141.4375,142.4375,143.4375,144.4375,145.3125,146.3125,147.3125,148.3125,149.3125,150.3125,151.375,152.3125,153.3125,154.4375,155.4375,156.4375,157.5,158.5,159.5625,160.625,161.5,162.5,163.5,164.4375,165.3125,166.1875,167.0625,167.875,168.75,169.5625,170.5625,171.5625,172.4375,173.25,174.125,175.125,176.125,177.125,178.0625,179.25,180.25,181.25,182.25,183.125,184.125,185.0625,186.0625,187.125,188.0625,189.125,190.1875,193.125,194.4375,198.1875,199.375,202.625,203.625,204.6875,205.6875,206.75,207.75,208.8125,209.8125,210.875,212.125,213.3125,214.3125,215.3125,216.25,217.3125,218.1875,219,219.9375,220.875,221.75,222.75,225.6875,226.6875,227.625,228.625,229.5,230.3125,231.1875,232,233,234.125,235.125,236.125,237.125,238.1875,239.1875,240.1875,241.5,243,246.875,251.1875,256.1875,258.5625,259.5625,260.5625,261.9375,263,263.875,264.8125,265.75,266.875,267.875,268.875,269.875,270.8125,271.75,272.625,273.5,274.3125,275.1875,276.0625,277.0625,278,278.8125,279.8125,280.875,281.8125,282.8125,283.6875,284.5,285.5,286.5625,287.5625,288.625,289.5625,290.5625,291.5625,292.5625,293.375,298.25,299.625,302.375,303.375,304.5,305.5625,306.5625,307.625,308.6875,310.125,311.3125,312.3125,313.3125,314.25,315.3125,316.375,317.4375,318.5,319.4375,320.4375,321.4375,322.4375,323.4375,324.875,325.875,326.875,328.125,329.125,330,331.0625,332.0625,333.125,334.1875,335.25,336.3125,337.3125,338.3125,339.375,340.375,341.3125,342.3125,343.375,344.4375,345.5,346.5625,347.625,348.6875,349.6875,350.75,351.8125,353,354,355.1875,356.1875,357.1875,358.1875,359.25],"SensorReading_Radii":[706,696,673,660,648,636,625,611,604,592,582,575,566,556,550,544,538,529,523,513,509,506,503,494,492,488,484,481,476,474,473,467,466,464,460,457,456,451,447,447,447,445,444,444,444,443,441,439,438,437,437,436,436,434,438,437,437,437,437,441,443,437,443,443,445,447,446,448,451,456,457,458,461,467,466,467,470,474,478,484,489,491,497,499,506,510,515,522,529,536,540,547,554,560,571,583,591,601,610,626,633,644,663,674,690,711,728,750,767,793,305,306,294,294,295,294,292,288,286,283,278,276,275,323,349,379,1119,513,515,512,510,512,511,513,529,537,538,519,518,511,509,523,223,180,157,165,129,106,108,113,103,116,115,114,121,117,117,112,113,113,115,115,113,114,114,117,117,117,118,119,121,147,180,205,206,206,210,213,218,220,185,165,160,153,148,200,244,252,257,263,269,271,257,255,258,296,290,277,286,292,289,283,275,259,266,269,271,274,276,263,263,256,259,260,259,258,266,188,217,221,219,220,220,220,220,224,217,216,217,183,169,150,137,126,131,131,134,139,304,306,310,314,308,283,293,311,327,336,347,341,341,340,338,340,339,337,336,336,335,335,336,336,335,313,264,265,321,324,321,315,312,310,306,304,300,1,633,633,638,639,651,650,647,647,645,643,639,642,639,637,637,636,623,619,629,628,647,633,612,529,533,626,656,662,664,669,672,675,677,686,689,691,695,703,709,713,721,725,728,736,745,757,765,771,789,788,768,749,726,715,698,683],"SensorReading_SignalStrength":[183,183,191,199,191,183,191,191,191,199,199,199,191,191,191,199,191,191,191,191,191,199,191,199,199,199,199,199,199,199,199,199,199,191,191,191,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,199,199,199,199,199,199,191,191,191,199,199,191,199,199,199,199,199,199,191,199,199,199,191,191,191,191,191,191,191,191,191,199,191,191,191,191,191,191,191,191,191,191,183,191,191,191,191,175,183,183,175,183,199,199,199,199,199,199,191,191,199,191,98,183,183,191,159,191,191,191,199,191,183,183,191,191,191,199,191,191,175,199,191,199,199,175,199,199,183,191,199,199,191,191,199,191,199,199,191,199,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,199,159,199,199,199,199,191,199,199,191,199,191,191,98,159,84,167,84,199,191,175,183,191,191,191,183,167,175,191,191,199,199,199,199,199,199,199,191,98,183,199,199,199,199,199,199,191,191,191,191,191,191,191,199,167,159,84,70,65,112,199,199,191,191,199,199,191,183,191,199,199,199,199,199,199,199,199,199,199,199,199,191,199,199,183,191,199,199,191,199,199,199,191,199,199,199,35,159,98,191,199,191,191,191,199,191,175,183,191,191,191,183,199,191,191,199,191,183,175,175,183,191,167,191,191,191,191,191,191,191,191,183,191,191,183,183,183,191,191,191,183,183,183,183,183,191,183,183,183,183,191,183,191]},{"TimeStamp":1496454234895,"SensorReading_Angles":[0.3125,1.375,2.375,3.4375,4.5,5.5625,6.5625,7.5,8.5,9.5,10.5625,11.5,12.5,13.5625,14.5,15.5625,16.5,17.5625,18.625,19.6875,20.5625,21.375,22.4375,23.3125,24.125,25.125,26.125,27.125,28.0625,29.0625,29.9375,30.9375,31.875,32.9375,33.9375,34.875,35.8125,36.8125,37.8125,38.8125,39.875,40.75,41.625,42.4375,43.4375,44.4375,45.3125,46.125,47,47.9375,48.9375,49.9375,51,52,52.875,53.75,54.75,55.8125,56.6875,57.6875,58.6875,59.5625,60.5625,61.5625,62.5625,63.5625,64.5,65.4375,66.125,67.125,68.0625,68.875,69.75,70.5625,71.4375,72.25,73.25,74.25,75.125,76.125,77.125,78.1875,79.1875,80.125,81.125,82.1875,83.125,84,85.0625,86.0625,87.0625,88.125,89.125,90.1875,91.1875,92.25,93.3125,94.4375,95.4375,96.5,97.5,98.5,99.5625,100.5625,101.6875,102.9375,105.5625,106.5625,107.5625,108.5,109.5,110.5,111.3125,112.3125,113.375,114.3125,115.3125,116.3125,117.25,118.3125,119.375,120.4375,121.5,125.75,126.75,127.8125,128.8125,129.875,130.75,131.9375,132.9375,133.875,134.875,135.9375,137,138.125,139.375,142,142.875,143.6875,144.6875,145.6875,146.625,147.625,148.625,149.625,150.625,151.6875,152.75,153.8125,154.875,155.9375,156.9375,157.9375,158.875,159.8125,160.8125,161.75,162.5625,163.4375,164.25,165.125,166,166.8125,167.6875,168.5,169.375,170.375,171.375,172.3125,173.125,174,174.8125,175.6875,176.6875,177.5625,178.5625,179.5625,180.4375,181.3125,182.125,183,183.9375,184.9375,185.9375,186.875,187.875,188.9375,190,191,193.8125,195.1875,198.875,199.875,200.875,201.9375,202.875,203.8125,204.75,205.6875,206.6875,207.625,208.4375,209.4375,210.3125,211.3125,212.3125,213.25,214.1875,215.125,216.125,217.125,217.9375,218.8125,219.8125,220.6875,221.5625,222.375,223.375,224.625,225.625,226.625,227.5,228.3125,229.1875,230.0625,230.875,231.75,232.75,233.75,234.6875,235.625,236.625,237.625,238.6875,239.6875,240.75,243.9375,247.875,252.25,257.1875,258.1875,259.0625,259.9375,260.8125,262.1875,263.1875,264.125,265.125,266.1875,267.25,268.375,269.25,270.125,271.125,272.125,273.0625,273.9375,274.75,275.625,276.625,277.625,278.6875,279.5625,280.5625,281.375,282.375,283.375,284.3125,285.3125,286.25,287.25,288.25,289.1875,290.125,291.125,292.125,293.125,297.9375,301.9375,302.9375,303.9375,304.875,305.875,306.875,308,309,310.1875,311.1875,312.5,313.5,314.5,315.5625,316.5625,317.5,318.5,319.5625,320.625,321.6875,322.6875,323.75,324.8125,325.875,327.3125,328.5,329.5,330.4375,331.4375,332.4375,333.5,334.5625,335.625,336.6875,337.75,338.9375,339.9375,341.125,342.125,343.125,344.0625,345.125,346.1875,347.25,348.3125,349.375,350.4375,351.5,352.5625,353.625,354.6875,355.75,356.8125,357.875,358.9375,360],"SensorReading_Radii":[666,648,639,626,617,609,598,589,582,572,565,559,553,546,538,530,523,519,512,508,499,496,495,492,488,486,480,477,477,469,465,465,469,461,459,458,457,452,451,450,449,447,448,445,447,447,442,444,444,444,445,444,446,446,445,444,447,447,450,451,451,453,457,455,458,461,466,464,468,470,471,476,478,481,482,485,489,496,499,505,510,513,519,524,528,538,544,549,557,566,571,580,587,600,606,620,632,640,656,669,680,699,714,732,747,772,302,301,298,296,295,290,289,287,283,279,279,282,285,324,349,329,374,458,511,511,512,511,510,516,536,536,533,515,517,511,522,203,157,157,153,106,106,110,114,104,117,116,112,116,117,115,114,113,111,114,114,114,112,114,115,116,117,117,118,119,122,140,175,206,206,206,208,211,216,218,210,168,162,160,146,148,192,246,250,258,260,269,271,278,260,263,286,289,271,278,278,277,293,292,288,287,284,283,283,282,277,277,277,276,265,259,260,267,258,257,256,268,263,200,214,260,235,222,222,222,221,224,228,243,244,252,196,175,157,145,135,126,128,133,181,308,309,311,312,315,299,282,301,320,330,343,344,340,343,342,339,339,337,338,336,334,332,336,334,334,327,269,262,308,322,319,313,312,307,306,303,300,616,629,634,635,636,645,643,644,642,637,638,633,637,637,639,634,633,617,621,633,636,635,635,535,528,516,651,659,663,664,669,673,679,679,685,689,696,700,706,715,721,724,728,738,746,757,766,773,791,786,769,750,730,715,698,681,667],"SensorReading_SignalStrength":[191,191,191,191,191,191,191,199,191,191,191,191,191,191,191,191,191,191,191,199,199,199,199,199,199,191,199,199,199,199,199,191,191,199,191,199,199,199,199,191,199,199,199,199,199,199,199,199,199,199,199,191,199,199,191,199,191,191,191,199,199,191,199,191,199,199,191,199,199,191,199,199,199,199,199,199,199,199,191,191,191,191,191,191,191,191,191,199,191,191,191,199,199,199,191,191,191,191,191,191,191,183,191,183,183,175,112,191,191,199,199,199,199,199,191,199,191,191,191,191,191,191,183,70,191,191,191,191,199,175,175,191,191,191,191,191,183,112,199,199,199,191,199,191,191,199,191,191,199,191,191,191,199,199,191,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,199,199,199,199,199,199,199,199,191,191,191,191,191,112,167,84,199,191,191,191,199,191,199,199,199,199,191,199,191,199,191,199,199,199,199,199,199,199,199,199,199,199,159,175,199,199,199,199,199,199,199,199,191,191,199,183,183,183,191,199,98,70,70,60,199,199,199,199,167,199,199,191,183,183,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,191,191,199,191,199,191,191,191,191,199,199,191,35,70,191,199,199,191,191,191,191,167,191,159,191,191,191,191,191,191,191,191,191,183,183,175,191,175,159,191,191,183,191,191,199,191,183,191,183,183,183,183,191,191,191,183,191,183,183,183,183,183,175,175,191,191,183,183,183]},{"TimeStamp":1496454235367,"SensorReading_Angles":[0.875,1.875,2.875,3.9375,5.0625,6.125,7,8,9,10,10.9375,11.9375,13,14.0625,15.125,16.1875,17.1875,18.25,19.25,20.1875,21.0625,22.125,22.9375,23.9375,24.9375,25.8125,26.6875,27.5,28.375,29.375,30.3125,31.25,32.25,33.25,34.0625,35.0625,36.0625,36.9375,37.9375,39,39.9375,40.9375,41.875,42.8125,43.8125,44.75,45.6875,46.6875,47.625,48.625,49.5625,50.5625,51.5625,52.5625,53.625,54.5,55.5,56.5,57.3125,58.3125,59.3125,60.3125,61.1875,62.1875,63.1875,64.1875,65.1875,66,66.875,67.6875,68.5625,69.375,70.375,71.375,72.3125,73.3125,74.25,75.3125,76.3125,77.25,78.25,79.1875,80.125,81.125,82.125,83.125,84.125,85.1875,86.25,87.1875,88.0625,89.0625,90.0625,91.0625,92.0625,93.0625,94.125,95.1875,96.3125,97.375,98.4375,99.5,100.5625,101.6875,102.75,103.6875,104.75,105.75,106.6875,107.5625,108.4375,109.25,110.25,111.1875,112.1875,113.125,114.125,115.0625,117,121.875,123.0625,124.0625,125.125,126.125,127.1875,128.25,129.3125,130.375,131.4375,132.5,133.5625,134.625,135.6875,136.75,137.75,139.375,140.375,141.375,142.375,143.375,144.5,145.5625,146.5625,147.5,148.5,149.4375,150.4375,151.5,152.5,153.5625,154.5,155.5,156.5,157.3125,158.3125,159.3125,160.1875,161,161.875,162.75,163.5625,164.4375,165.25,166.125,167,167.9375,168.9375,169.875,170.75,171.6875,172.6875,173.625,174.5,175.4375,176.4375,177.4375,178.375,179.1875,180.0625,180.875,182.0625,183.0625,184.125,185,185.875,186.8125,187.8125,189.6875,190.875,192.0625,193.5625,196.75,201.125,202.0625,203.3125,204.5,205.6875,208.0625,209.0625,210,211.1875,213.6875,214.6875,215.5,216.5,217.4375,218.4375,219.25,220.25,221.625,224.8125,225.8125,226.6875,227.5625,228.4375,229.25,230.125,230.9375,231.8125,232.8125,233.625,234.625,235.6875,236.75,237.8125,238.75,242.5,246.375,250.875,255.8125,258.25,259.3125,260.5625,261.5625,262.5625,263.5625,264.5625,265.5625,266.5,267.5,268.5,269.5,270.4375,271.25,272.25,273.25,274.1875,275.0625,276.0625,277.0625,278,279,279.875,280.875,282.0625,282.9375,283.8125,284.75,285.8125,286.6875,287.5,288.5,289.375,290.1875,291.1875,292.125,297,301.875,302.875,303.875,304.875,305.875,306.875,308,309.1875,310.1875,311.375,312.375,313.375,314.4375,315.5,316.5625,317.4375,318.4375,319.4375,320.4375,321.4375,322.4375,323.6875,324.6875,325.875,328.8125,329.8125,330.8125,331.875,332.9375,334,335.0625,336.125,337.1875,338.25,339.3125,340.375,341.3125,342.375,343.4375,344.5,345.5,346.5625,347.625,348.6875,349.6875,350.75,351.8125,352.8125,353.875,354.875,355.875,356.875,357.9375,358.9375,359.875],"SensorReading_Radii":[653,640,629,620,611,599,595,582,576,568,559,553,546,539,535,521,520,516,508,504,502,496,495,494,488,483,481,479,475,474,470,467,467,467,463,461,459,455,455,454,455,453,453,452,449,449,451,450,450,450,451,451,453,452,453,452,454,454,458,460,460,461,461,465,465,471,475,475,476,480,483,487,489,489,495,500,507,511,515,521,526,532,537,545,549,559,563,573,579,587,594,602,613,625,635,646,659,671,687,703,720,739,761,776,306,310,305,301,298,298,297,293,293,290,287,284,283,280,296,348,1117,516,515,516,513,511,508,516,523,540,540,518,514,514,514,234,182,153,164,105,104,113,110,109,118,117,113,115,118,110,113,115,109,110,112,113,113,113,115,113,115,116,116,117,121,148,180,193,204,207,211,209,210,215,219,164,163,158,150,145,180,246,248,255,258,267,271,271,250,253,249,268,285,276,275,265,274,263,255,256,259,271,255,246,252,253,258,258,257,239,184,203,202,205,206,206,207,206,204,206,206,213,179,166,145,134,129,128,130,154,294,292,310,307,289,283,304,326,335,342,340,340,339,337,339,336,338,335,336,334,334,334,335,335,313,264,264,315,319,317,311,309,307,305,303,302,1,627,634,633,636,642,644,642,644,643,630,637,638,639,634,635,621,619,636,627,635,632,593,527,519,644,660,666,669,672,677,678,686,688,695,699,705,712,717,722,729,733,744,753,763,768,778,792,780,757,738,725,706,696,679,664],"SensorReading_SignalStrength":[183,183,191,191,191,199,191,199,191,191,191,191,191,191,191,191,191,199,199,199,191,199,199,199,199,199,199,191,199,199,199,199,199,199,199,199,199,199,199,199,191,199,199,199,199,199,191,199,199,191,199,199,199,191,199,191,199,199,199,191,191,191,199,199,199,191,191,199,199,199,199,199,199,199,199,191,191,191,191,199,191,191,199,199,199,191,191,191,191,199,199,199,191,183,191,191,191,199,191,183,183,183,183,183,167,199,183,191,199,199,199,199,199,199,199,199,199,191,159,45,175,175,191,191,191,191,191,183,191,191,183,183,191,191,191,167,191,199,199,191,199,199,191,199,191,191,199,191,199,191,191,191,199,199,199,191,199,199,199,199,199,199,199,199,199,199,191,199,199,199,199,199,199,199,199,183,199,199,199,199,191,199,183,199,199,191,199,191,175,159,159,98,70,191,191,167,183,112,191,191,191,112,191,199,191,199,199,199,199,183,98,191,199,199,199,199,199,199,199,191,191,191,183,191,191,199,84,70,70,60,112,191,183,191,191,191,191,191,199,191,199,199,191,199,199,199,191,199,199,199,199,199,199,199,183,199,199,191,191,199,199,199,199,191,191,199,35,65,199,199,191,199,199,199,159,191,183,175,191,191,191,199,199,191,183,191,191,183,183,183,191,98,183,183,191,199,183,191,183,183,167,191,183,183,183,183,183,191,191,191,175,183,175,183,183,183,191,183,183,191,183,191]},{"TimeStamp":1496454235911,"SensorReading_Angles":[0.6875,1.6875,2.625,3.625,4.6875,5.6875,6.6875,7.75,8.6875,9.6875,10.75,11.75,12.8125,13.875,14.8125,15.8125,16.8125,17.875,18.6875,19.6875,20.6875,21.6875,22.875,23.9375,24.9375,25.875,26.875,27.9375,28.8125,29.75,30.75,31.75,32.6875,33.5,34.375,35.1875,36.1875,37.1875,38.25,39.25,40.125,41.125,42.125,43.125,44.0625,45.0625,46.0625,47.0625,48.125,49.0625,50,51,52,52.9375,53.875,54.875,55.875,56.8125,57.8125,58.8125,59.875,60.8125,61.75,62.75,63.6875,64.6875,65.625,66.3125,67.125,68,68.8125,69.6875,70.5,71.375,72.1875,73.0625,74,75,76,77.0625,78.125,79.1875,80.0625,81.0625,82.0625,83,84.0625,85.125,86.1875,87.125,87.9375,88.9375,90,91.0625,92.125,93.1875,94.25,95.375,96.4375,97.5,98.5625,99.6875,100.75,101.8125,104.3125,105.3125,106.375,107.25,108.125,109.125,110.25,111.25,112.25,113.25,114.3125,115.3125,117.9375,122.8125,124.375,125.3125,126.3125,127.3125,128.3125,129.3125,130.375,131.5625,132.5,133.5625,134.5625,135.625,136.625,137.6875,138.875,139.875,140.875,141.6875,142.5625,143.5625,144.5,145.5,146.5,147.5625,148.5625,149.625,150.6875,151.75,152.8125,153.75,154.8125,155.8125,156.75,157.75,158.625,159.625,160.625,161.5,162.375,163.1875,164.0625,164.9375,165.75,166.625,167.4375,168.4375,169.4375,170.4375,171.4375,172.5,173.3125,174.3125,175.3125,176.375,177.5,178.375,179.1875,180.1875,181,182,183,183.9375,185,186,186.9375,187.875,189.0625,191.9375,193.3125,196.75,200.6875,201.625,202.5625,203.875,205,206,207.0625,208,209,210.125,211.5,212.5,213.5,214.375,215.25,216.0625,216.875,217.75,218.5625,219.4375,220.5625,221.5625,224.5,225.5,226.4375,227.25,228.125,229,229.8125,230.8125,231.8125,232.875,233.875,234.9375,235.875,236.8125,237.8125,238.8125,242.375,243.6875,247.9375,252.6875,257.375,258.4375,259.375,260.375,261.375,262.375,263.3125,264.1875,265.1875,266.1875,267.1875,268.125,269.125,270.125,271.125,272,273,274,275,276,276.875,277.875,278.875,279.875,280.9375,282.0625,282.9375,283.9375,284.9375,285.9375,286.9375,287.875,288.875,289.875,290.8125,291.6875,292.6875,297.5625,301.5625,302.625,303.6875,304.75,305.8125,306.875,308,310.5,311.8125,312.8125,313.875,314.9375,315.8125,316.8125,317.8125,318.75,319.75,320.6875,321.6875,322.75,325.25,326.4375,327.4375,328.4375,329.4375,330.3125,331.375,332.3125,333.3125,334.25,335.3125,336.375,337.4375,338.5,339.5625,340.625,341.6875,342.75,343.8125,344.8125,345.875,346.8125,347.875,348.9375,350,351.0625,352.125,353.1875,354.25,355.3125,356.375,357.4375,358.5,359.5625],"SensorReading_Radii":[652,640,631,617,610,602,594,583,573,569,561,554,543,539,537,526,520,516,510,507,501,497,496,490,489,484,478,477,472,474,469,468,464,464,461,461,457,456,454,456,455,453,450,452,451,451,451,451,448,448,450,451,450,451,452,452,453,459,458,455,461,461,463,466,466,468,472,473,477,481,480,485,488,490,495,498,504,511,511,518,524,531,534,541,549,556,562,569,578,588,594,600,610,620,633,644,656,668,687,705,717,736,754,770,307,304,300,301,299,297,295,292,287,286,283,280,289,358,516,517,515,515,514,510,511,523,543,541,526,516,516,515,520,225,174,156,166,113,105,108,113,104,118,117,117,117,116,116,112,118,115,113,115,111,114,115,115,116,117,118,118,120,124,151,180,199,209,209,210,212,215,220,184,165,160,157,146,169,244,248,251,259,266,268,271,251,251,265,290,278,278,281,283,284,284,254,256,272,273,273,273,264,258,258,255,260,256,256,259,259,186,217,217,216,217,218,216,218,218,215,214,204,181,168,147,137,125,122,131,136,261,294,304,309,302,291,285,304,316,332,343,342,340,339,339,337,337,336,336,336,334,334,332,334,331,300,262,271,322,317,315,312,307,306,302,300,298,613,628,636,633,643,644,644,644,641,636,639,636,635,638,634,620,620,636,629,639,634,535,538,656,654,661,663,669,672,672,679,684,690,690,696,702,706,710,720,729,735,740,747,757,767,781,791,789,763,746,729,714,695,681,668],"SensorReading_SignalStrength":[183,191,183,191,191,191,199,191,199,191,191,199,191,191,191,191,191,191,191,199,199,199,191,199,199,191,191,191,199,199,199,199,199,199,199,199,191,191,199,191,199,199,191,191,191,199,199,191,191,199,199,191,199,199,199,199,199,199,199,199,191,191,199,199,199,199,191,199,199,199,199,199,199,199,199,199,199,199,191,191,191,199,199,191,191,191,191,191,199,199,191,191,191,191,191,191,191,191,191,183,191,191,191,175,112,191,199,199,199,199,199,199,199,199,191,199,183,50,167,191,191,191,191,191,191,175,191,191,183,191,183,191,183,191,191,199,199,191,199,199,183,191,191,191,191,191,191,191,199,191,199,199,199,199,199,199,199,199,199,199,199,199,199,191,199,199,199,199,199,199,199,199,159,199,199,199,199,191,191,191,183,199,199,199,191,98,167,84,70,191,199,167,175,191,183,191,199,183,159,183,199,191,199,199,199,199,199,199,199,191,98,183,199,199,199,199,199,199,183,191,191,183,199,183,191,199,84,167,70,70,60,199,199,191,183,199,191,191,191,191,191,199,199,199,199,199,199,199,199,199,199,199,199,199,199,183,199,199,191,199,191,199,191,199,199,199,191,60,70,191,199,199,183,191,191,112,167,199,191,191,199,191,191,191,191,191,183,183,112,183,175,199,191,191,191,191,191,183,183,191,191,183,183,183,191,191,191,183,191,191,175,183,183,183,183,183,183,183,191,183,183,191]}]}'; -------------------------------------------------------------------------------- /examples/line_extraction/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 20 | 21 | 22 | 44 | 45 | 46 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 71 | 72 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /examples/line_extraction/js/components/Data.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************//** 2 | ** Data (Module): 3 | * A LineExtractionApp module that provides a collection of classes/structs/methods to assist 4 | * in the instantiation and storage of various data point representations. 5 | ****************************************************************************************/ 6 | LineExtractionApp.Data = function () { 7 | 8 | /**************************************************************************************** 9 | * Classes + Structs 10 | ****************************************************************************************/ 11 | // a small struct to define an entire scan (360 degrees) worth of sensor readings 12 | let ScanDataStruct = function (sensorReadings, timeStamp) { 13 | this.sensorReadings = sensorReadings; 14 | this.timeStamp = (arguments.length < 2) ? Date.now() : timeStamp; 15 | }; 16 | 17 | //a small struct to define polar coordinate 18 | function PolarCoordStruct(theAngle, theRadius) { 19 | this.angle = theAngle; 20 | this.radius = theRadius; 21 | }; 22 | 23 | //a small struct to define a cartesian coordinate 24 | function CartesianCoordStruct(x, y, z) { 25 | this.x = x; 26 | this.y = y; 27 | this.z = z; 28 | }; 29 | 30 | // (Class) An individual data point reading from the sensor. 31 | // Includes both polar and cartesian representations. 32 | function SensorReading(theAngle, theDistance, theSignalStrength) { 33 | //store both the polar and cartesian forms of the data point 34 | this.polarCoord = new PolarCoordStruct(theAngle, theDistance); 35 | this.cartesianCoord = polar2Cart(theAngle, theDistance); 36 | 37 | this.signalStrength = theSignalStrength; 38 | this.timeStamp = Date.now(); 39 | }; 40 | 41 | //returns true if the data point is within the provided radius range (inclusive) 42 | SensorReading.prototype.isInRadiusRange = function (min, max) { 43 | let bBigEnough = this.polarCoord.radius >= min; 44 | let bSmallEnough = this.polarCoord.radius <= max; 45 | return bBigEnough && bSmallEnough; 46 | }; 47 | 48 | //returns true if the data point is within the provided angle range (inclusive) 49 | SensorReading.prototype.isInAngleRange = function (min, max) { 50 | let bBigEnough = this.polarCoord.angle >= min; 51 | let bSmallEnough = this.polarCoord.angle <= max; 52 | return bBigEnough && bSmallEnough; 53 | }; 54 | 55 | //returns true if the data point registered a signal strength within the provided range (inclusive) 56 | SensorReading.prototype.isInSignalStrengthRange = function (min, max) { 57 | let bBigEnough = this.signalStrength >= min; 58 | let bSmallEnough = this.signalStrength <= max; 59 | return bBigEnough && bSmallEnough; 60 | }; 61 | 62 | SensorReading.prototype.toString = function () { 63 | let msg = 64 | `DataPoint: 65 | TimeStamp: ${this.timeStamp} 66 | Signal Strength: ${this.signalStrength} 67 | PolarCoord: ${this.polarCoord.toString()} 68 | CartCoord: ${this.cartesianCoord.toString()}`; 69 | return msg; 70 | }; 71 | 72 | 73 | /************************************************************************************//** 74 | ** DataPlayback (Class): A LineExtractionApp module class. 75 | * Controls the playback of data 76 | ****************************************************************************************/ 77 | let DataPlayback = function () { 78 | /**************************************************************************************** 79 | * Instance Variables 80 | ****************************************************************************************/ 81 | this.data; 82 | this.numScans; 83 | this.currentIndex; 84 | 85 | /**************************************************************************************** 86 | * Methods 87 | ****************************************************************************************/ 88 | this.init = (recordingData) => { 89 | this.reset(); 90 | if (typeof recordingData !== 'undefined') { 91 | this.setData(recordingData); 92 | } 93 | }; 94 | 95 | //draw the scan at a specific index (as if it was received from the sensor) 96 | this.drawScan = (index) => { 97 | if (index >= this.numScans) 98 | return; 99 | // Fire an event to alert any subscribers that a new scan is to be drawn 100 | LineExtractionApp.EventDispatcher.trigger('event_CollectedCompleteScanData', this.data[index]); 101 | }; 102 | 103 | this.cycle = () => { 104 | if (this.numScans <= 0) 105 | return; 106 | 107 | this.drawScan(this.currentIndex); 108 | 109 | let nextDeltaTime = this.timeUntilNextIndex(this.currentIndex); 110 | 111 | //check if the index will rollover 112 | if (nextDeltaTime < 0) { 113 | //reset the index to 0 114 | this.currentIndex = 0; 115 | } 116 | else { 117 | this.currentIndex++; 118 | } 119 | //call the next cycle in the appropriate amount of time 120 | setTimeout(() => { this.cycle(); }, nextDeltaTime); 121 | }; 122 | 123 | this.timeUntilNextIndex = (theIndex) => { 124 | //example 125 | let nextIndex = (theIndex >= (this.numScans - 1)) ? 0 : theIndex + 1; 126 | let timeStamp_Index = this.data[theIndex].timeStamp; 127 | let timeStamp_nextIndex = this.data[nextIndex].timeStamp; 128 | let deltaMillis = timeStamp_nextIndex - timeStamp_Index; 129 | return deltaMillis; 130 | }; 131 | 132 | this.setData = (newData) => { 133 | this.data = newData; 134 | this.numScans = this.data.length; 135 | }; 136 | 137 | // resets the playback 138 | this.reset = () => { 139 | this.data = null; 140 | this.numScans = 0; 141 | this.currentIndex = 0; 142 | }; 143 | }; 144 | 145 | 146 | /**************************************************************************************** 147 | * Methods 148 | ****************************************************************************************/ 149 | //converts a polar coordinate to a 2D cartesian coordinate 150 | let polar2Cart = (theAngle_deg, theRadius) => { 151 | let x = theRadius * Math.cos(deg2Rad(theAngle_deg)); 152 | let y = theRadius * Math.sin(deg2Rad(theAngle_deg)); 153 | return new CartesianCoordStruct(x, y, 0); 154 | }; 155 | 156 | //converts an anlge from degrees to radians 157 | let deg2Rad = (theAngle_deg) => { 158 | return theAngle_deg * (Math.PI / 180); 159 | }; 160 | 161 | //compatability crutch in case the date.now is unsupported 162 | if (!Date.now) { 163 | Date.now = function () { return new Date().getTime(); } 164 | }; 165 | 166 | 167 | //Comparators for sorting arrays of sensor readings 168 | let compareRadius = (a, b) => { 169 | if (a.polarCoord.radius < b.polarCoord.radius) 170 | return -1; 171 | if (a.polarCoord.radius > b.polarCoord.radius) 172 | return 1; 173 | return 0; 174 | }; 175 | 176 | //Helper functions to help when filtering an array of sensor readings using array.filter 177 | let radiusCheck = (min, max) => { 178 | return function (element) { return element.isInRadiusRange(min, max); } 179 | }; 180 | 181 | // removes sensor readings from a scan struct that are within a specified radius 182 | let removeSensorReadingsInsideRadius = (scan, radius) => { 183 | scan.sensorReadings = scan.sensorReadings.filter(radiusCheck(radius, Number.MAX_SAFE_INTEGER)); 184 | }; 185 | 186 | 187 | 188 | /**************************************************************************************** 189 | Sub-Modules 190 | ****************************************************************************************/ 191 | 192 | /************************************************************************************//** 193 | ** ScanFile (Module): A LineExtractionApp Data module. 194 | * Provides methods to interpret JSON objects into datapoints. 195 | ****************************************************************************************/ 196 | let ScanFile = function () { 197 | /**************************************************************************************** 198 | * Methods 199 | ****************************************************************************************/ 200 | // interprets a json object into an array of scans according to the known scan data json format 201 | let interpretJSONData = (jsonObject) => { 202 | let numScans; 203 | let allScans = []; 204 | let bLogTimeStampPerScan = jsonObject.bLogTimeStampPerSweep; 205 | 206 | if (!bLogTimeStampPerScan) { 207 | console.error("Not handling this kind of recording yet"); 208 | return null; 209 | } 210 | 211 | numScans = jsonObject.Sweeps.length; 212 | //loop through each scan 213 | for (let i = 0; i < numScans; i++) { 214 | //grab all the data for that scan 215 | let theTimeStamp = jsonObject.Sweeps[i].TimeStamp; 216 | let theAngles = jsonObject.Sweeps[i].SensorReading_Angles; 217 | let theRadii = jsonObject.Sweeps[i].SensorReading_Radii; 218 | let theSignalStrengths = jsonObject.Sweeps[i].SensorReading_SignalStrength; 219 | 220 | let numSensorReadings = theAngles.length; 221 | let allSensorReadings = []; 222 | //loop through each sensor reading in the scan 223 | for (let j = 0; j < numSensorReadings; j++) { 224 | //create a sensor reading class from the limited data and then store it 225 | allSensorReadings.push(new SensorReading(theAngles[j], theRadii[j], theSignalStrengths[j])); 226 | } 227 | //store all the sensor reading instances for this scan in a scan data struct 228 | allScans.push(new ScanDataStruct(allSensorReadings, theTimeStamp)); 229 | } 230 | return allScans; 231 | }; 232 | 233 | 234 | /************************************************************************************//** 235 | ** Public API 236 | * Return all the methods/variables that should be public. 237 | ****************************************************************************************/ 238 | return { 239 | //public methods 240 | interpretJSONData: interpretJSONData 241 | }; 242 | }(); 243 | 244 | 245 | /************************************************************************************//** 246 | ** Public API 247 | * Return all the methods/variables that should be public. 248 | ****************************************************************************************/ 249 | return { 250 | // public sub-modules 251 | ScanFile: ScanFile, 252 | 253 | // public classes/structs 254 | ScanDataStruct: ScanDataStruct, 255 | PolarCoordStruct: PolarCoordStruct, 256 | CartesianCoordStruct: CartesianCoordStruct, 257 | SensorReading: SensorReading, 258 | DataPlayback: DataPlayback, 259 | 260 | // public methods 261 | polar2Cart: polar2Cart, 262 | deg2Rad: deg2Rad, 263 | compareRadius: compareRadius, 264 | radiusCheck: radiusCheck, 265 | removeSensorReadingsInsideRadius: removeSensorReadingsInsideRadius 266 | }; 267 | 268 | }(); -------------------------------------------------------------------------------- /examples/line_extraction/js/components/EventDispatcher.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************//** 2 | ** EventDispatcher (Module): 3 | * Provides methods for subscribing/publishing events. 4 | * This allows decoupling of the app modules from the control logic. 5 | ****************************************************************************************/ 6 | LineExtractionApp.EventDispatcher = function () { 7 | 8 | let eventSubscriptions = {}; 9 | 10 | let subscribe = (eventName, callback) => { 11 | // Get any current subscribers for eventName 12 | let subscribers = eventSubscriptions[eventName]; 13 | 14 | if (typeof subscribers === 'undefined') { 15 | // If the event has no subscribers, initialize the subscribers array 16 | subscribers = eventSubscriptions[eventName] = []; 17 | } 18 | 19 | // Add the given callback function to the end of the array with 20 | // eventSubscriptions for this event. 21 | subscribers.push(callback); 22 | }; 23 | 24 | let trigger = (eventName, data) => { 25 | // Get any current subscribers for the triggered event 26 | let subscribers = eventSubscriptions[eventName]; 27 | 28 | if (typeof subscribers === 'undefined') { 29 | //console.log(`[EventDispatcher] trigger: no subscribers for event ${eventName}`); 30 | // If the event has no subscribers, return early (ie: don't fire event) 31 | return; 32 | } 33 | 34 | // Send the data for each subscriber of this event 35 | subscribers.forEach(function (subscriber) { 36 | subscriber(data || {}); 37 | }); 38 | 39 | //console.log(`[EventDispatcher] trigger: event ${eventName} dispatched to ${subscribers.length} subscribers, with data: ${data}`); 40 | } 41 | 42 | 43 | /************************************************************************************//** 44 | ** Public API 45 | * Return all the methods/variables that should be public. 46 | ****************************************************************************************/ 47 | return { 48 | // public methods 49 | subscribe: subscribe, 50 | trigger: trigger 51 | }; 52 | 53 | }(); -------------------------------------------------------------------------------- /examples/line_extraction/js/components/Graphics.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************//** 2 | ** Graphics (Module): A LineExtractionApp Module 3 | * Module for visualizing scan data graphically using webgl via THREE.js. 4 | ****************************************************************************************/ 5 | LineExtractionApp.Graphics = function () { 6 | /**************************************************************************************** 7 | * Module Includes 8 | ****************************************************************************************/ 9 | const _EXTRACTION = LineExtractionApp.Perception.PrimitiveExtraction; 10 | const _FILTERING = LineExtractionApp.Processing.Filtering; 11 | const _HELPERS = LineExtractionApp.Utils.GenericHelpers; 12 | 13 | /************************************************************************************//** 14 | ** PointCloudObject (Class): A LineExtractionApp Graphics module class. 15 | * A point cloud object. 16 | ****************************************************************************************/ 17 | let PointCloudObject = function (theNumPoints, parent, distanceScale) { 18 | 19 | this.distanceScale = distanceScale; 20 | // Base64 encoded png sprite of a small disc 21 | let discSprite = new Image(); 22 | discSprite.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sHDgwCEMBJZu0AAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAABM5JREFUWMO1V0tPG2cUPZ4Hxh6DazIOrjFNqJs0FIMqWFgWQkatsmvVbtggKlSVRVf5AWz4AWz4AUSKEChll19QJYSXkECuhFxsHjEhxCYm+DWGMZ5HF72DJq4bAzFXurI0M/I5997v3u9cC65vTJVn2lX/xHINQOYSBLTLEuIuCWw4Z3IGAEvf6ASmVHjNzHCXBG4A0AjACsAOwEbO0nsFQBnAGYASAIl+ZRMR7SolMEdsByD09fV5R0ZGgg8ePPjW5/N1iqLYpuu6RZblciKR2I9Go69evnwZnZ+fjwI4IS8AKBIRzeQfJWCANwKwh0KhtrGxsYehUOin1tbW+zzP23ietzY2NnIAoGmaLsuyUiqVyvl8XtrY2NiamZn589mzZxsAUgCOAeQAnFI2tI+VxIjaAeDzoaGh7xYWFuZOTk6OZVk+12uYqqq6JEnn0Wg0OT4+/geAXwGEAdwDIFJQXC1wO4DWR48e/RCPxxclSSroVzRFUbSDg4P848ePFwH8DuAhkWih83TRQWxFOXgAwvDwcOfo6OhvXV1d39tsNtuVBwTDWBwOh1UUxVsMw1hXVlbSdCgNV43uYSvrHg6H24aHh38eHBz85TrgF9FYLHA4HLzH43FvbW2d7u/vG+dANp8FpqIlbd3d3V8Fg8EfBUFw4BONZVmL3+9vHhkZCQL4AoAHgJPK8G+yzC0XDofdoVAo5PP5vkadTBAEtr+/39ff3x8gAp/RPOEqx2qjx+NpvXv3bk9DQ0NDvQgwDIOWlhZrMBj8kgi0UJdxRgYMArzL5XJ7vd57qLPZ7Xamp6fnNgBXtQxcjFuHw+Hyer3t9SYgCAITCAScAJoBNNEY/08GOFVVrfVMv7kMNDntFD1vjIAPrlRN0xjckOm6biFQ3jwNPwDMZrOnqVTqfb3Bi8Wivru7W/VCYkwPlKOjo0IikXh7EwQikYgE4Nw0CfXKDCipVCoTj8df3QABbW1tLUc6oUgkFPMkVACUNjc337148eKvw8PDbJ2jP1taWkoCyNDVXDSECmNSK4qiKNLq6urW8+fPI/UicHx8rD59+jSVy+WOAKSJhKENwFItLtoxk8mwsixzHR0dHe3t7c5PAU+n09rs7OzJkydPYqVSaQfANoDXALIk31S2smU1TWMPDg7K5XKZ7+3t9TudTut1U7+wsFCcmJiIpdPpbQBxADsAknQWymYCOukBHYCuKApisdhpMpnURFEU79y503TVyKenpzOTk5M7e3t7MQKPV0Zv1gNm+awB0MvlshqLxfLb29uyJElWURSbXC4XXyvqxcXFs6mpqeTc3Nzu3t7e3wQcA7BPZ8Cov1pNlJplmQtAG8MwHV6v95tAINA5MDBwPxAIuLu6upr8fr/VAN3c3JQjkcjZ+vp6fnl5+d2bN29SuVzuNYAEpf01CdRChUL+X1VskHACuA3Ay3Fcu9vt7nA6nZ7m5uYWQRCaNE3jVVW15PP580KhIGUymWw2m00DOAJwSP4WwPtq4LX2Ao6USxNlQyS/RcQcdLGwlNIz6vEMAaZpNzCk2Pll94LK/cDYimxERiBwG10sxjgvEZBE0UpE6vxj+0Ct5bTaXthgEhRmja8QWNkkPGsuIpfdjpkK+cZUWTC0KredVmtD/gdlSl6EG4AMvQAAAABJRU5ErkJggg==' 23 | let discTexture = new THREE.Texture(); 24 | discSprite.onload = function () { 25 | discTexture.image = discSprite; 26 | discTexture.needsUpdate = true; 27 | }; 28 | 29 | /**************************************************************************************** 30 | * Methods 31 | ****************************************************************************************/ 32 | this.createPointsObject = (numPoints) => { 33 | //creates a new points object which contains a pointcloud and 34 | //associated attributes for representing a scan 35 | let initialPositions = new Float32Array(numPoints * 3); 36 | let initialAlphas = new Float32Array(numPoints); 37 | for (let i = 0; i < numPoints; i++) { 38 | initialPositions[i * 3 + 0] = 0; 39 | initialPositions[i * 3 + 1] = 0; 40 | initialPositions[i * 3 + 2] = 0; 41 | initialAlphas[i] = 0.0; 42 | }; 43 | 44 | let points_geometry = new THREE.BufferGeometry(); 45 | points_geometry.addAttribute('position', new THREE.Float32BufferAttribute(initialPositions, 3)); 46 | points_geometry.addAttribute('alpha', new THREE.Float32BufferAttribute(initialAlphas, 1)); 47 | points_geometry.dynamic = true; 48 | 49 | let material = new THREE.ShaderMaterial({ 50 | uniforms: { 51 | color: { value: new THREE.Color(0xff0000) }, 52 | texture: { value: discTexture }, 53 | sizeAtNominalDistance: { value: 4.0 }, // in pixels 54 | nominalDistance: { value: 50.0 }, // in world units 55 | minSize: { value: 4.0 } // in pixels 56 | }, 57 | vertexShader: document.getElementById('vertexshader').textContent, 58 | fragmentShader: document.getElementById('fragmentshader').textContent, 59 | alphaTest: 0.9, 60 | transparent: true 61 | }); 62 | 63 | return new THREE.Points(points_geometry, material); 64 | }; 65 | 66 | this.setDataFromScan = (scan) => { 67 | let dataPoints = scan.sensorReadings; 68 | let numDataPoints = dataPoints.length; 69 | 70 | if (this.numPoints < numDataPoints) { 71 | console.log(`There are ${this.numPoints} vertices in the point cloud and ${numDataPoints} recordings in this scan. Adding more vertices to the point cloud.`); 72 | log.verbose(`There are ${this.numPoints} vertices in the point cloud and ${numDataPoints} recordings in this scan. Adding more vertices to the point cloud.`); 73 | this.changePointCloudSize(numDataPoints + Math.ceil(0.25 * numDataPoints)); 74 | } 75 | 76 | //Change point positions and make them visible 77 | let dataPoint; 78 | let col; 79 | let attributes = this.points.geometry.attributes; 80 | for (let i = 0; i < numDataPoints; i++) { 81 | dataPoint = dataPoints[i]; 82 | attributes.position.array[i * 3 + 0] = this.distanceScale * dataPoint.cartesianCoord.x; 83 | attributes.position.array[i * 3 + 1] = this.distanceScale * dataPoint.cartesianCoord.y; 84 | attributes.position.array[i * 3 + 2] = this.distanceScale * dataPoint.cartesianCoord.z; 85 | 86 | attributes.alpha.array[i] = 1.0; 87 | } 88 | this.points.geometry.computeBoundingSphere(); 89 | 90 | //hide any unused points that were previously visible 91 | for (let i = numDataPoints; i < this.numVisiblePoints; i++) { 92 | attributes.position.array[i * 3 + 0] = 0; 93 | attributes.position.array[i * 3 + 1] = 0; 94 | attributes.position.array[i * 3 + 2] = 0; 95 | attributes.alpha.array[i] = 0.0; 96 | } 97 | this.numVisiblePoints = numDataPoints; 98 | this.updateVertFlags(); 99 | }; 100 | 101 | this.changePointCloudSize = (numPoints) => { 102 | // changes the size (quantity of data points) of the point cloud, 103 | // effectively permitting the display of numPoints sensor readings 104 | this.parent.remove(this.points); 105 | this.points = this.createPointsObject(numPoints); 106 | this.numPoints = numPoints; 107 | this.numVisiblePoints = 0; 108 | this.parent.add(this.points); 109 | }; 110 | 111 | this.updateVertFlags = () => { 112 | //Flag the geometry attributes (Shader Attributes), indicating that values need an update 113 | let attributes = this.points.geometry.attributes; 114 | attributes.position.needsUpdate = true; 115 | attributes.alpha.needsUpdate = true; 116 | }; 117 | 118 | this.getNumPoints = () => { 119 | return this.numPoints; 120 | }; 121 | 122 | this.getNumVisiblePoints = () => { 123 | return this.numVisiblePoints; 124 | }; 125 | 126 | this.getPoints = () => { 127 | return this.points; 128 | }; 129 | 130 | this.clear = () => { 131 | let attributes = this.points.geometry.attributes; 132 | for (let i = 0; i < this.numPoints; i++) { 133 | attributes.position.array[i * 3 + 0] = 0; 134 | attributes.position.array[i * 3 + 1] = 0; 135 | attributes.position.array[i * 3 + 2] = 0; 136 | attributes.alpha.array[i] = 0.0; 137 | } 138 | this.numVisiblePoints = 0; 139 | this.updateVertFlags(); 140 | }; 141 | 142 | this.destroy = () => { 143 | this.parent.remove(this.points); 144 | this.parent = null; 145 | this.points = null; 146 | this.numPoints = null; 147 | this.numVisiblePoints = null; 148 | }; 149 | 150 | /**************************************************************************************** 151 | * Attributes 152 | ****************************************************************************************/ 153 | this.parent = parent; 154 | this.points = this.createPointsObject(theNumPoints); 155 | this.numPoints = theNumPoints; 156 | this.numVisiblePoints = 0; 157 | this.parent.add(this.points); 158 | }; 159 | 160 | /************************************************************************************//** 161 | ** Visualizer (Class): A LineExtractionApp Graphics module class. 162 | * Manages the graphical visualization of scan data. 163 | * Uses WebGL via THREE.js. 164 | ****************************************************************************************/ 165 | let Visualizer = function () { 166 | this.distanceScale = 0.1; 167 | 168 | this.$container; 169 | this.WIDTH; 170 | this.HEIGHT; 171 | 172 | this.scene; 173 | this.renderer; 174 | 175 | this.camera; 176 | this.pointCloud; 177 | 178 | this.MAT_line = 179 | this.extractedLines; 180 | this.lineExtractor; 181 | 182 | this.init = (containerID) => { 183 | 184 | //adjust the canvas size whenever the window is resized 185 | window.addEventListener('resize', this.onCanvasResize, false); 186 | 187 | // get the DOM element to attach to. 188 | this.$container = $(`#${containerID}`); 189 | 190 | //grab the dimensions of the containing div 191 | this.WIDTH = this.$container.innerWidth(); 192 | this.HEIGHT = this.$container.innerHeight(); 193 | 194 | // create a scene 195 | this.scene = new THREE.Scene(); 196 | 197 | // create a WebGL renderer 198 | try { 199 | this.renderer = new THREE.WebGLRenderer(); 200 | } 201 | catch (err) { 202 | console.error(err); 203 | alert(err); 204 | return; 205 | } 206 | 207 | // start the renderer 208 | this.renderer.setSize(this.WIDTH, this.HEIGHT); 209 | // attach the render-supplied DOM element 210 | this.$container.append(this.renderer.domElement); 211 | 212 | // Init Camera 213 | this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); 214 | this.camera.position.z = 100; 215 | 216 | // Create an ambient light 217 | let ambientLight = new THREE.AmbientLight(0xFFFFFF); 218 | this.scene.add(ambientLight); 219 | 220 | // Create a point cloud object to draw scans 221 | this.pointCloud = new PointCloudObject(500, this.scene, this.distanceScale); 222 | 223 | // Create a line extractor 224 | this.initLineExtractor(); 225 | 226 | // Create an array to hold lines 227 | this.extractedLines = []; 228 | // Create a line material 229 | this.MAT_line = new THREE.LineBasicMaterial({ color: 0xffffff }); 230 | }; 231 | 232 | this.initLineExtractor = () => { 233 | // Create the actual line extractor 234 | this.lineExtractor = new _EXTRACTION.LineExtractor( 235 | // Line extraction method 236 | _EXTRACTION.LineExtractionTechniqueEnum.SPLIT_MERGE, 237 | // SPLIT-MERGE line extractor params 238 | { 239 | distanceThreshold: 20, 240 | collinearityThreshold: 2000, 241 | bUseIntermediateLineFitting: false 242 | }, 243 | // Sensor Reading Pre-Processor Params 244 | { 245 | minRadius: 50, 246 | filter: _FILTERING.FilterTechniqueEnum.MEDIAN_1D, 247 | filterParams: _HELPERS.checkParams({}, _FILTERING.FilterParameterDefaults.MEDIAN_1D) 248 | }, 249 | // Line Post-Processor Params 250 | { 251 | minSetSize: 5 252 | } 253 | ); 254 | }; 255 | 256 | // extract lines from the scan data and draw it to the visualizer 257 | this.extractLines = (scan) => { 258 | // remove any existing lines 259 | this.removeExtractedLines(); 260 | 261 | // extract the lines 262 | let lines = this.lineExtractor.extractLines(scan); 263 | 264 | // draw the extracted lines 265 | for (let i = 0, len = lines.length; i < len; i++) { 266 | let startPt = lines[i].lineSegmentStartPt; 267 | let endPt = lines[i].lineSegmentEndPt; 268 | this.drawExtractedLine(new THREE.Vector3(startPt.x, startPt.y, 0), new THREE.Vector3(endPt.x, endPt.y, 0)); 269 | } 270 | }; 271 | 272 | // remove extracted lines 273 | this.removeExtractedLines = () => { 274 | while (this.extractedLines.length > 0) { 275 | this.scene.remove(this.extractedLines.shift()); 276 | } 277 | }; 278 | 279 | // draws an extracted line 280 | this.drawExtractedLine = (startPt, endPt) => { 281 | let geometry = new THREE.BufferGeometry(); 282 | let positions = new Float32Array(2 * 3); 283 | positions[0] = startPt.x * this.distanceScale; 284 | positions[1] = startPt.y * this.distanceScale; 285 | positions[2] = startPt.z * this.distanceScale; 286 | positions[3 + 0] = endPt.x * this.distanceScale; 287 | positions[3 + 1] = endPt.y * this.distanceScale; 288 | positions[3 + 2] = endPt.z * this.distanceScale; 289 | 290 | geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3)); 291 | 292 | let line = new THREE.Line(geometry, this.MAT_line); 293 | this.extractedLines.push(line); 294 | this.scene.add(line); 295 | }; 296 | 297 | // check that a scan contains a sensor readings array with at least 1 reading 298 | this.checkScanIsValid = (scan) => { 299 | if (scan.sensorReadings === undefined || scan.sensorReadings.length === undefined || scan.sensorReadings.length < 1) 300 | return false; 301 | return true; 302 | }; 303 | 304 | //draws a single new scan to the visualizer 305 | this.drawSingleScan = (scan) => { 306 | if (this.checkScanIsValid(scan) === false) 307 | return; 308 | 309 | // Update the data for the point cloud 310 | this.pointCloud.setDataFromScan(scan); 311 | 312 | this.extractLines(scan); 313 | }; 314 | 315 | //update the canvas and camera whenever the window is resized 316 | this.onCanvasResize = () => { 317 | //retrieve the new dimensions of the canvas' parent div 318 | this.WIDTH = this.$container.innerWidth(); 319 | this.HEIGHT = this.$container.innerHeight(); 320 | 321 | //update the aspect ratio of the cameras 322 | if (this.camera) { 323 | this.camera.aspect = this.WIDTH / this.HEIGHT; 324 | this.camera.updateProjectionMatrix(); 325 | } 326 | 327 | //update the size of the canvas to fill its parent div 328 | this.renderer.setSize(this.WIDTH, this.HEIGHT); 329 | }; 330 | 331 | this.animate = () => { 332 | requestAnimationFrame(this.animate); 333 | this.render(); 334 | }; 335 | 336 | this.render = () => { 337 | //render the scene 338 | this.renderer.render(this.scene, this.camera); 339 | }; 340 | 341 | 342 | }; 343 | 344 | /************************************************************************************//** 345 | ** Public API 346 | * Return all the methods/variables that should be public. 347 | ****************************************************************************************/ 348 | return { 349 | // Public Classes 350 | Visualizer: Visualizer 351 | }; 352 | }(); -------------------------------------------------------------------------------- /examples/line_extraction/js/components/Perception.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************//** 2 | ** Perception (Module): 3 | * A LineExtractionApp module that provides a collection of classes/structs/methods to assist 4 | * perception tasks from 2D lidar scans. Currently only basic boundary extraction is 5 | * implmented, using the Split-Merge line extraction algorithm. 6 | ****************************************************************************************/ 7 | LineExtractionApp.Perception = function () { 8 | /**************************************************************************************** 9 | * Includes and Constants 10 | ****************************************************************************************/ 11 | const _HELPERS = LineExtractionApp.Utils.GenericHelpers; 12 | const _POINT_2D_UTILS = LineExtractionApp.Processing.Point2DUtils; 13 | const _SENSOR_READING_UTILS = LineExtractionApp.Processing.SensorReadingUtils; 14 | const _FILTERING = LineExtractionApp.Processing.Filtering; 15 | 16 | /**************************************************************************************** 17 | Sub-Modules 18 | ****************************************************************************************/ 19 | 20 | /************************************************************************************//** 21 | ** PrimitiveExtraction (Module): 22 | * A LineExtractionApp module that provides a collection of classes/structs/methods to assist 23 | * in extracting primitives from 2D scan data (currently only line extraction) 24 | ****************************************************************************************/ 25 | let PrimitiveExtraction = function () { 26 | /**************************************************************************************** 27 | * Enums 28 | ****************************************************************************************/ 29 | const LineExtractionTechniqueEnum = { 30 | SPLIT_MERGE: 1, 31 | 32 | properties: { 33 | 1: { name: "SPLIT_MERGE", value: 1, displayName: "Iterative end point split-merge", bIsDefault: true } 34 | } 35 | }; 36 | 37 | /**************************************************************************************** 38 | * Defaults for various types of classes 39 | ****************************************************************************************/ 40 | const PreProcessorParameterDefaults = { 41 | SENSOR_READINGS: { 42 | minRadius: 50, 43 | filter: _FILTERING.FilterTechniqueEnum.NO_FILTER, 44 | filterParams: _FILTERING.FilterParameterDefaults.NO_FILTER 45 | } 46 | }; 47 | 48 | const PostProcessorParameterDefaults = { 49 | LINES: { 50 | minSetSize: 5 51 | } 52 | }; 53 | 54 | const LineExtractorParameterDefaults = { 55 | SPLIT_MERGE: { 56 | distanceThreshold: 20, 57 | collinearityThreshold: 2000, 58 | bUseIntermediateLineFitting: false 59 | } 60 | }; 61 | 62 | /**************************************************************************************** 63 | * Methods 64 | ****************************************************************************************/ 65 | // creates a line extractor of the specified type 66 | let createLineExtractor = (type, params) => { 67 | switch (type) { 68 | case LineExtractionTechniqueEnum.SPLIT_MERGE: 69 | return typeof params === 'undefined' ? new SplitMerge() : new SplitMerge(params); 70 | default: 71 | console.log(`The extraction method "${method}" does not exist, so defaulting to SPLIT MERGE`); 72 | return new SplitMerge(); 73 | } 74 | }; 75 | 76 | /**************************************************************************************** 77 | * Classes 78 | ****************************************************************************************/ 79 | // (Class) Pre Processes data points 80 | let SensorReadingsPreProcessor = function (params) { 81 | // verify and validate the processing parameters against the default values 82 | this.params = _HELPERS.checkParams(params, PreProcessorParameterDefaults.SENSOR_READINGS); 83 | // verify and validate the filter parameters against the default values for the specified filter 84 | let defaultFilterParamsKey = _FILTERING.FilterTechniqueEnum.properties[this.params.filter].parameterDefaultKey; 85 | this.params.filterParams = _HELPERS.checkParams(this.params.filterParams, _FILTERING.FilterParameterDefaults[defaultFilterParamsKey]) 86 | 87 | // perform processing according to the parameters 88 | this.process = (sensorReadings) => { 89 | // remove points inside the specified minimum radius 90 | let processed = _SENSOR_READING_UTILS.removePointsInsideRadius(sensorReadings, this.params.minRadius); 91 | // remove points with impossible bearings (azimuth value less than its predecessor) 92 | _SENSOR_READING_UTILS.removeReadingsWithImpossibleBearings(processed); 93 | // filter the readings if requested 94 | switch (this.params.filter) { 95 | case _FILTERING.FilterTechniqueEnum.NO_FILTER: 96 | break; 97 | case _FILTERING.FilterTechniqueEnum.MEDIAN_1D: 98 | processed = _FILTERING.medianFilter1D(processed, this.params.filterParams); 99 | break; 100 | default: 101 | break; 102 | } 103 | // return the processed readings 104 | return processed; 105 | }; 106 | 107 | 108 | this.setParams = (newParams) => { 109 | this.params = _HELPERS.checkParams(newParams, this.params); 110 | }; 111 | }; 112 | 113 | 114 | // (Class) Post Processes lines 115 | let LinePostProcessor = function (params) { 116 | // verify and validate the processing parameters against the default values 117 | this.params = _HELPERS.checkParams(params, PostProcessorParameterDefaults.LINES); 118 | 119 | // perform processing according to the parameters 120 | this.process = (lines) => { 121 | // remove any tiny sets (post-processing) 122 | for (let i = 0; i < lines.length; i++) { 123 | if (lines[i].sensorReadings.length < this.params.minSetSize) { 124 | lines.splice(i, 1); 125 | i--; 126 | } 127 | } 128 | return lines; 129 | }; 130 | 131 | this.setParams = (newParams) => { 132 | this.params = _HELPERS.checkParams(newParams, this.params); 133 | }; 134 | }; 135 | 136 | // (Class) Extracts lines from data points 137 | let LineExtractor = function (extractorType, extractorParams, preProcessorParams, postProcessorParams) { 138 | 139 | // INSTANCE VARIABLES: 140 | this.extractor = null; 141 | if (typeof extractorType === 'undefined') { 142 | this.extractor = createLineExtractor(_HELPERS.getEnumDefault(LineExtractionTechniqueEnum)); 143 | } 144 | else { 145 | this.extractor = typeof extractorParams === 'undefined' ? createLineExtractor(extractorType) : createLineExtractor(extractorType, extractorParams); 146 | } 147 | 148 | // create processors for pre/post processing (use defaults if the parameters are not specified) 149 | this.preProcessor = typeof preProcessorParams === 'undefined' ? new SensorReadingsPreProcessor() : new SensorReadingsPreProcessor(preProcessorParams); 150 | this.postProcessor = typeof postProcessorParams === 'undefined' ? new LinePostProcessor() : new LinePostProcessor(postProcessorParams); 151 | 152 | // METHODS: 153 | // Extracts lines given a ScanDataStruct 154 | // returns: an array of line objects 155 | this.extractLines = (scan) => { 156 | // convert the scan to a useable structure of points 157 | let sensorReadings = scan.sensorReadings; 158 | 159 | // pre-process the points 160 | sensorReadings = this.preProcessor.process(sensorReadings); 161 | if (sensorReadings.length <= 2) 162 | return []; 163 | 164 | // extract lines 165 | let lines = this.extractor.extractLines(sensorReadings); 166 | 167 | // post-process the lines 168 | lines = this.postProcessor.process(lines); 169 | 170 | return lines; 171 | }; 172 | 173 | // SETTERS: 174 | this.setParams = (extractorParams, preProcessorParams, postProcessorParams) => { 175 | this.setExtractorParams(extractorParams); 176 | this.setPreProcessorParams(preProcessorParams); 177 | this.setPostProcessorParams(postProcessorParams); 178 | }; 179 | this.setExtractorParams = (params) => { 180 | this.extractor.setParams(params); 181 | }; 182 | this.setPreProcessorParams = (params) => { 183 | this.preProcessor.setParams(params); 184 | }; 185 | this.setPostProcessorParams = (params) => { 186 | this.postProcessor.setParams(params); 187 | }; 188 | }; 189 | 190 | 191 | // (Class) Extracts lines from data points using a split-merge algorithm 192 | let SplitMerge = function (params) { 193 | 194 | // INSTANCE VARIABLES: 195 | // verify and validate the parameters against the default values 196 | this.params = _HELPERS.checkParams(typeof params === 'undefined' ? null : params, LineExtractorParameterDefaults.SPLIT_MERGE); 197 | this.params.distanceThresholdSquared = this.params.distanceThreshold * this.params.distanceThreshold; 198 | this.S; 199 | 200 | 201 | // METHODS: 202 | 203 | // extract lines from the current data points using the split-merge algorithm 204 | // return: an array of line objects 205 | this.extractLines = (sensorReadings) => { 206 | 207 | //initialize the set of lines to be empty 208 | this.S = [sensorReadings]; 209 | 210 | let mostDistantPair = _SENSOR_READING_UTILS.findMostDistantPair(sensorReadings); 211 | if (!mostDistantPair) return; 212 | 213 | // Split (step) 214 | //this.split( sensorReadings, mostDistantPair.startPtIndex, mostDistantPair.endPtIndex ); 215 | this.split(sensorReadings); 216 | 217 | // Merge (step) 218 | this.merge(); 219 | 220 | return this.S; 221 | }; 222 | 223 | // recursive split step of the SplitMerge algorithm 224 | //this.split = ( sensorReadings, startPtIndex, endPtIndex ) => { 225 | this.split = (sensorReadings) => { 226 | let numReadings = sensorReadings.length; 227 | if (numReadings === undefined || numReadings < 2) 228 | return; 229 | 230 | let lineStart, lineEnd; 231 | if (this.params.bUseIntermediateLineFitting) { 232 | let fit = _SENSOR_READING_UTILS.linearRegression(sensorReadings); 233 | let xLimits = _SENSOR_READING_UTILS.findXLimits(sensorReadings); 234 | lineStart = { x: xLimits.min, y: xLimits.min * fit.gradient + fit.intercept }; 235 | lineEnd = { x: xLimits.max, y: xLimits.max * fit.gradient + fit.intercept }; 236 | } 237 | else { 238 | let mostDistantPair = _SENSOR_READING_UTILS.findMostDistantPair(sensorReadings); 239 | if (!mostDistantPair) 240 | return; 241 | lineStart = sensorReadings[mostDistantPair.startPtIndex].cartesianCoord; 242 | lineEnd = sensorReadings[mostDistantPair.endPtIndex].cartesianCoord; 243 | } 244 | 245 | 246 | // Find the most distant point to the line 247 | let distanceResults = _SENSOR_READING_UTILS.findMostDistantPtToLine(sensorReadings, lineStart, lineEnd); 248 | 249 | let setIndex = this.S.indexOf(sensorReadings); 250 | 251 | // if distance > threshold, split and repeat with left and right point sets 252 | if (distanceResults.distSqrd > this.params.distanceThresholdSquared) { 253 | if (numReadings <= 2) 254 | return; 255 | 256 | // split 257 | let S1, S2; 258 | switch (distanceResults.index) { 259 | case 0: 260 | S1 = sensorReadings.slice(0, 1); 261 | S2 = sensorReadings.slice(1); 262 | break; 263 | case (numReadings - 1): 264 | S1 = sensorReadings.slice(0, distanceResults.index); 265 | S2 = sensorReadings.slice(distanceResults.index - 1); 266 | break; 267 | default: 268 | S1 = sensorReadings.slice(0, distanceResults.index + 1); 269 | S2 = sensorReadings.slice(distanceResults.index); 270 | break; 271 | } 272 | 273 | // replace the set in S with the two new sets 274 | this.S.splice(setIndex, 1, S1, S2); 275 | 276 | // recursively repeat with left and right point sets 277 | this.split(S1); 278 | this.split(S2); 279 | } 280 | else { 281 | let newSet = { 282 | sensorReadings: sensorReadings, 283 | lineSegmentStartPt: lineStart, 284 | lineSegmentEndPt: lineEnd 285 | }; 286 | let setIndex = this.S.indexOf(sensorReadings); 287 | this.S.splice(setIndex, 1, newSet); 288 | } 289 | return; 290 | }; 291 | 292 | // check if two segments are collinear and should be merged 293 | this.checkIfShouldMerge = (S1, S2) => { 294 | let collinearityMetric, mergedSensorReadings, fit, segStart, segEnd, distanceResults; 295 | 296 | // measure the two line's collinearity 297 | collinearityMetric = _POINT_2D_UTILS.collinearityTest( 298 | S1.lineSegmentStartPt, 299 | S1.lineSegmentEndPt, 300 | S2.lineSegmentStartPt, 301 | S2.lineSegmentEndPt); 302 | 303 | // if two consecutive segments are close/collinear enough 304 | if (collinearityMetric <= this.params.collinearityThreshold) { 305 | // temporarily merge the sets 306 | mergedSensorReadings = S1.sensorReadings.concat(S2.sensorReadings); 307 | // obtain the common line between the sets 308 | fit = _SENSOR_READING_UTILS.linearRegression(mergedSensorReadings); 309 | let xLimits = _SENSOR_READING_UTILS.findXLimits(mergedSensorReadings); 310 | segStart = { x: xLimits.min, y: xLimits.min * fit.gradient + fit.intercept }; 311 | segEnd = { x: xLimits.max, y: xLimits.max * fit.gradient + fit.intercept }; 312 | 313 | // Find the most distant point to the line 314 | distanceResults = _SENSOR_READING_UTILS.findMostDistantPtToLine(mergedSensorReadings, segStart, segEnd); 315 | 316 | //merge the segments if they're close 317 | if (distanceResults.distSqrd <= this.params.distanceThresholdSquared) { 318 | return { 319 | bShouldMerge: true, 320 | mergedObject: { 321 | sensorReadings: mergedSensorReadings, 322 | lineEquation: fit, 323 | lineSegmentStartPt: segStart, 324 | lineSegmentEndPt: segEnd 325 | } 326 | }; 327 | } 328 | } 329 | return { bShouldMerge: false }; 330 | }; 331 | 332 | // merge step of the SplitMerge algorithm 333 | this.merge = () => { 334 | // remove any sets without a line 335 | for (let i = this.S.length - 1; i >= 0; i--) { 336 | if (!this.S[i].hasOwnProperty("sensorReadings")) 337 | this.S.splice(i, 1); 338 | } 339 | 340 | let S1, S2; 341 | let i = 0; 342 | while (i < this.S.length - 1) { 343 | // take two consecutive segments 344 | S1 = this.S[i]; 345 | S2 = this.S[i + 1]; 346 | 347 | let mergeCheck = this.checkIfShouldMerge(S1, S2); 348 | if (mergeCheck.bShouldMerge) { 349 | //replace the first set with the merged set 350 | this.S[i] = mergeCheck.mergedObject; 351 | //remove the second set 352 | this.S.splice(i + 1, 1); 353 | } 354 | else { 355 | i++; 356 | } 357 | } 358 | 359 | // check for collinearity of the two rollover consecutive segments (to either side of the 0/360 angle) 360 | if (this.S.length >= 2) { 361 | // take first and last segments 362 | S1 = this.S[0]; 363 | S2 = this.S[this.S.length - 1]; 364 | 365 | let mergeCheck = this.checkIfShouldMerge(S1, S2); 366 | if (mergeCheck.bShouldMerge) { 367 | //replace the first set with the merged set 368 | this.S[0] = mergeCheck.mergedObject; 369 | //remove the second set 370 | this.S.splice(this.S.length - 1, 1); 371 | } 372 | } 373 | }; 374 | 375 | // SETTERS: 376 | // specify any new parameters 377 | this.setParams = (newParams) => { 378 | this.params = _HELPERS.checkParams(newParams, this.params); 379 | this.params.distanceThresholdSquared = this.params.distanceThreshold * this.params.distanceThreshold; 380 | }; 381 | 382 | }; 383 | 384 | 385 | /************************************************************************************//** 386 | ** Public API --- primitive extraction sub-module 387 | * Return all the methods/variables that should be public. 388 | ****************************************************************************************/ 389 | return { 390 | // public enums 391 | LineExtractionTechniqueEnum: LineExtractionTechniqueEnum, 392 | 393 | // public classes 394 | LineExtractor: LineExtractor, 395 | SensorReadingsPreProcessor: SensorReadingsPreProcessor, 396 | LinePostProcessor: LinePostProcessor 397 | }; 398 | }(); 399 | 400 | 401 | 402 | /************************************************************************************//** 403 | ** Public API --- perception module 404 | * Return all the methods/variables that should be public. 405 | ****************************************************************************************/ 406 | return { 407 | // public sub-modules 408 | PrimitiveExtraction: PrimitiveExtraction 409 | }; 410 | }(); -------------------------------------------------------------------------------- /examples/line_extraction/js/components/Plotting.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************//** 2 | ** Plotting (Module): A LineExtractionApp module. 3 | * Structures relevant ot plotting 2D graphs of sensor data. 4 | ****************************************************************************************/ 5 | LineExtractionApp.Plotting = function () { 6 | /**************************************************************************************** 7 | * Includes 8 | ****************************************************************************************/ 9 | const _FILTERING = LineExtractionApp.Processing.Filtering; 10 | 11 | /************************************************************************************//** 12 | ** Graph Manager (Class): A LineExtractionApp Graph module class. 13 | * Manages the graphs which display data 14 | ****************************************************************************************/ 15 | let GraphManager = function () { 16 | /**************************************************************************************** 17 | * Instance Variables 18 | ****************************************************************************************/ 19 | // holds the previous drawn scan 20 | this.lastScan; 21 | // defines configuration options for the plotly graphs 22 | this.plotlyConfigurationOptions 23 | // the id for the HTML div elements that serve as containers for the plots 24 | this.cartesianPlotContainerID; 25 | this.polarPlotContainerID; 26 | // the data and layout for both plots 27 | this.polarData; 28 | this.polarLayout; 29 | this.cartesianData; 30 | this.cartesianLayout; 31 | 32 | /**************************************************************************************** 33 | * Methods 34 | ****************************************************************************************/ 35 | // initialize the graph manager 36 | this.init = (cartesianPlotContainerID, polarPlotContainerID) => { 37 | this.lastScan = null; 38 | this.cartesianPlotContainerID = cartesianPlotContainerID; 39 | this.polarPlotContainerID = polarPlotContainerID; 40 | //create and initialize some settings 41 | this.initPlotlyConfigOptions(); 42 | //initialize the graphs 43 | this.initPlotlyGraphs(cartesianPlotContainerID, polarPlotContainerID); 44 | }; 45 | 46 | // init plotly config options to some default values 47 | this.initPlotlyConfigOptions = () => { 48 | this.plotlyConfigurationOptions = { 49 | // no interactivity, for export or image generation 50 | staticPlot: true, 51 | // new users see some hints about interactivity 52 | showTips: false, 53 | // enable axis pan/zoom drag handles 54 | showAxisDragHandles: false, 55 | // enable direct range entry at the pan/zoom drag points (drag handles must be enabled above) 56 | showAxisRangeEntryBoxes: false, 57 | // display the mode bar (true, false, or 'hover') 58 | displayModeBar: false, 59 | // add the plotly logo on the end of the mode bar 60 | displaylogo: false 61 | }; 62 | }; 63 | 64 | this.initPlotlyGraphs = () => { 65 | let tracePolar = { 66 | x: [], 67 | y: [], 68 | mode: 'lines+markers', 69 | type: 'scatter' 70 | }; 71 | this.polarData = [tracePolar]; 72 | this.polarLayout = { title: `Polar Coordinates`, xaxis: { title: 'azimuth (degrees)' }, yaxis: { title: 'range (cm)' } }; 73 | Plotly.newPlot(this.polarPlotContainerID, this.polarData, this.polarLayout, this.plotlyConfigurationOptions); 74 | let traceCartesian = { 75 | x: [], 76 | y: [], 77 | mode: 'lines+markers', 78 | type: 'scatter' 79 | }; 80 | this.cartesianData = [traceCartesian]; 81 | this.cartesianLayout = { title: `2D Cartesian Coordinates`, xaxis: { title: 'x (cm)' }, yaxis: { title: 'y (cm)' } }; 82 | Plotly.newPlot(this.cartesianPlotContainerID, this.cartesianData, this.cartesianLayout, this.plotlyConfigurationOptions); 83 | }; 84 | 85 | this.clear = () => { 86 | this.plotSensorReadings([], false); 87 | this.plotSensorReadings([], true); 88 | }; 89 | 90 | // Updates the graphs with data from the specified scan 91 | this.update = (scan) => { 92 | //store the scan 93 | this.lastScan = scan; 94 | 95 | // check the scan is valid 96 | if (!scan.sensorReadings) { 97 | this.clear(); 98 | return; 99 | } 100 | 101 | let filterParams = { bPadBoundaries: false, windowSize: 3 }; 102 | let filteredReadings = _FILTERING.medianFilter1D(scan.sensorReadings, filterParams); 103 | 104 | this.plotSensorReadings(filteredReadings, false /*plot polar*/); 105 | this.plotSensorReadings(filteredReadings, true /*plot cartesian*/); 106 | }; 107 | 108 | // Refresh the graphs (used when filters are updated) with the existing data 109 | this.refreshGraphs = () => { 110 | if (this.lastScan) 111 | this.update(this.lastScan); 112 | }; 113 | 114 | this.getPlotlyData = (sensorReadings, bCartesian) => { 115 | let abscissa = []; // horizontal axis -> x (cartesian) or azimuth (polar) 116 | let ordinate = []; // vertical axis -> y (cartesian) or radius (polar) 117 | for (let i = 0, len = sensorReadings.length; i < len; i++) { 118 | abscissa.push(bCartesian ? sensorReadings[i].cartesianCoord.x : sensorReadings[i].polarCoord.angle); 119 | ordinate.push(bCartesian ? sensorReadings[i].cartesianCoord.y : sensorReadings[i].polarCoord.radius); 120 | } 121 | return { abscissa: abscissa, ordinate: ordinate }; 122 | }; 123 | 124 | this.plotSensorReadings = (sensorReadings, bCartesian) => { 125 | let coords = this.getPlotlyData(sensorReadings, bCartesian); 126 | let trace = { 127 | x: coords.abscissa, 128 | y: coords.ordinate, 129 | mode: 'lines+markers', 130 | type: 'scatter' 131 | }; 132 | if (bCartesian) { 133 | this.cartesianData[0] = trace; 134 | Plotly.redraw(this.cartesianPlotContainerID); 135 | } 136 | else { 137 | this.polarData[0] = trace; 138 | Plotly.redraw(this.polarPlotContainerID); 139 | } 140 | }; 141 | }; 142 | 143 | /************************************************************************************//** 144 | ** Public API 145 | * Return all the methods/variables that should be public. 146 | ****************************************************************************************/ 147 | return { 148 | // Public Classes 149 | GraphManager: GraphManager 150 | }; 151 | 152 | }(); -------------------------------------------------------------------------------- /examples/line_extraction/js/components/Processing.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************//** 2 | ** Processing (Module): 3 | * A LineExtractionApp module that provides a collection of classes/structs/methods to assist 4 | * in processing 2D lidar data. 5 | ****************************************************************************************/ 6 | LineExtractionApp.Processing = function () { 7 | /**************************************************************************************** 8 | * Includes 9 | ****************************************************************************************/ 10 | const _HELPERS = LineExtractionApp.Utils.GenericHelpers; 11 | const _DATA = LineExtractionApp.Data; 12 | 13 | /**************************************************************************************** 14 | Sub-Modules 15 | ****************************************************************************************/ 16 | 17 | /************************************************************************************//** 18 | ** Point2DUtils (Module): 19 | * A LineExtractionApp module that provides a collection of classes/structs/methods to assist 20 | * in operations with basic 2D point objects (objects with x and y fields) 21 | ****************************************************************************************/ 22 | let Point2DUtils = function () { 23 | /**************************************************************************************** 24 | * Methods 25 | ****************************************************************************************/ 26 | 27 | let sqr = (x) => { return x * x }; 28 | let dist2 = (v, w) => { return sqr(v.x - w.x) + sqr(v.y - w.y) }; 29 | 30 | // returns the squared distance from a point (p) to the line segment defined by end pts (v, w) 31 | let distToSegmentSquared = (p, v, w) => { 32 | let l2 = dist2(v, w); 33 | if (l2 == 0) return dist2(p, v); 34 | let t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2; 35 | t = Math.max(0, Math.min(1, t)); 36 | return dist2(p, { 37 | x: v.x + t * (w.x - v.x), 38 | y: v.y + t * (w.y - v.y) 39 | }); 40 | }; 41 | 42 | // returns a rough metric for the collinearity of 2 segments defined by end pts (A->B, C->D) 43 | let collinearityTest = (A, B, C, D) => { 44 | let temp1 = (Math.abs((A.x - B.x) * (C.y - D.y) - (C.x - D.x) * (A.y - B.y))); 45 | let temp2 = (Math.abs((A.x - C.x) * (B.y - D.y) - (B.x - D.x) * (A.y - C.y))); 46 | let temp3 = (Math.abs((A.x - D.x) * (C.y - B.y) - (C.x - B.x) * (A.y - D.y))); 47 | return (temp1 + temp2 + temp3) / 3; 48 | }; 49 | 50 | // returns the square of the distance between two points 51 | let squaredDistBetweenPts = (A, B) => { 52 | return (B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y); 53 | } 54 | 55 | /************************************************************************************//** 56 | ** Public API --- points sub-module 57 | * Return all the methods/variables that should be public. 58 | ****************************************************************************************/ 59 | return { 60 | // public methods 61 | distToSegmentSquared: distToSegmentSquared, 62 | collinearityTest: collinearityTest, 63 | squaredDistBetweenPts: squaredDistBetweenPts, 64 | }; 65 | 66 | }(); 67 | 68 | /************************************************************************************//** 69 | ** SensorReadingUtils (Module): 70 | * A LineExtractionApp module that provides a collection of classes/structs/methods to assist 71 | * in operations with basic SensorReading objects. 72 | ****************************************************************************************/ 73 | let SensorReadingUtils = function () { 74 | /**************************************************************************************** 75 | * Methods 76 | ****************************************************************************************/ 77 | // remove readings from an array of readings based on the radius 78 | let removePointsInsideRadius = (readings, radius) => { 79 | return readings.filter(_DATA.radiusCheck(radius, Number.MAX_SAFE_INTEGER)); 80 | }; 81 | 82 | // removes error readings whose bearings are less than the previous 83 | // return: none, performed in place on array 84 | let removeReadingsWithImpossibleBearings = (readings) => { 85 | let bearing; 86 | let lastBearing = -1; 87 | for (let i = 0, len = readings.length; i < len; i++) { 88 | bearing = readings[i].polarCoord.angle; 89 | 90 | if (bearing <= lastBearing) { 91 | //let nextBearing = (typeof readings[i+1] === 'undefined') ? `no more bearing this scan`: readings[i+1].polarCoord.angle; 92 | //console.log(`Error at index ${i}: bearing window [${lastBearing}, ${bearing}, ${nextBearing}]`); 93 | readings.splice(i, 1); 94 | len--; 95 | } 96 | else { 97 | lastBearing = bearing; 98 | } 99 | } 100 | }; 101 | 102 | // returns the median radius from an array of sensor readings 103 | let findMedianRadius = (sensorReadings, middleIndex) => { 104 | sensorReadings.sort(_DATA.compareRadius); 105 | return sensorReadings[middleIndex].polarCoord.radius; 106 | }; 107 | 108 | // returns the indices and distance between the two most distant points in the array of sensorReadings 109 | let findMostDistantPair = (sensorReadings) => { 110 | let result = { 111 | startPtIndex: null, 112 | endPtIndex: null, 113 | squaredDistance: -1 114 | } 115 | let tempDistSqrd; 116 | 117 | // for each pair of segments in L 118 | for (let i = 0, len = sensorReadings.length; i < len; i++) { 119 | for (let j = i + 1; j < len; j++) { 120 | let tempDistSqrd = Point2DUtils.squaredDistBetweenPts(sensorReadings[i].cartesianCoord, sensorReadings[j].cartesianCoord); 121 | if (tempDistSqrd > result.squaredDistance) { 122 | result.startPtIndex = i; 123 | result.endPtIndex = j; 124 | result.squaredDistance = tempDistSqrd; 125 | } 126 | } 127 | } 128 | return (result.squaredDistance >= 0) ? result : null; 129 | }; 130 | 131 | // returns the index and distance of the most distant reading to a line segmenet defined by end pts 132 | let findMostDistantPtToLine = (sensorReadings, lineSegStart, lineSegEnd) => { 133 | // Find the most distant point to the line 134 | let biggestSoFar = 0; 135 | let indexOfBiggestSoFar = -1; 136 | let tempDist; 137 | for (let i = 0, len = sensorReadings.length; i < len; i++) { 138 | tempDist = Point2DUtils.distToSegmentSquared(sensorReadings[i].cartesianCoord, lineSegStart, lineSegEnd); 139 | if (tempDist > biggestSoFar) { 140 | biggestSoFar = tempDist; 141 | indexOfBiggestSoFar = i; 142 | } 143 | } 144 | 145 | return { 146 | index: indexOfBiggestSoFar, 147 | distSqrd: biggestSoFar 148 | } 149 | }; 150 | 151 | // returns the min and max X values in an array of sensorReadings 152 | let findXLimits = (sensorReadings) => { 153 | let limits = { 154 | min: Number.MAX_SAFE_INTEGER, 155 | max: -Number.MAX_SAFE_INTEGER 156 | } 157 | let xCoord; 158 | for (let i = 0, len = sensorReadings.length; i < len; i++) { 159 | xCoord = sensorReadings[i].cartesianCoord.x; 160 | if (xCoord < limits.min) 161 | limits.min = xCoord; 162 | if (xCoord > limits.max) 163 | limits.max = xCoord; 164 | } 165 | return limits; 166 | }; 167 | 168 | // performs a basic linear regression 169 | // returns a slope & intercept eqn of a line (y = mx+b) that best describes the sensor readings 170 | let linearRegression = (data) => { 171 | let sum = [0, 0, 0, 0], n = 0, results = []; 172 | for (; n < data.length; n++) { 173 | if (data[n].cartesianCoord.x != null) { 174 | sum[0] += data[n].cartesianCoord.x; 175 | sum[1] += data[n].cartesianCoord.y; 176 | sum[2] += data[n].cartesianCoord.x * data[n].cartesianCoord.x; 177 | sum[3] += data[n].cartesianCoord.x * data[n].cartesianCoord.y; 178 | //sum[4] += data[n].y * data[n].y; 179 | } 180 | } 181 | let gradient = (n * sum[3] - sum[0] * sum[1]) / (n * sum[2] - sum[0] * sum[0]); 182 | let intercept = (sum[1] / n) - (gradient * sum[0]) / n; 183 | return { gradient: gradient, intercept: intercept }; 184 | }; 185 | 186 | 187 | /************************************************************************************//** 188 | ** Public API --- sensor reading utils sub-module 189 | * Return all the methods/variables that should be public. 190 | ****************************************************************************************/ 191 | return { 192 | // public methods 193 | removePointsInsideRadius: removePointsInsideRadius, 194 | removeReadingsWithImpossibleBearings: removeReadingsWithImpossibleBearings, 195 | 196 | findMedianRadius: findMedianRadius, 197 | 198 | findMostDistantPair: findMostDistantPair, 199 | findMostDistantPtToLine: findMostDistantPtToLine, 200 | linearRegression: linearRegression, 201 | findXLimits: findXLimits 202 | }; 203 | }(); 204 | 205 | /************************************************************************************//** 206 | ** Filtering (Module): 207 | * A LineExtractionApp module that provides a collection of classes/structs/methods to assist 208 | * in filtering 2D lidar data. 209 | ****************************************************************************************/ 210 | let Filtering = function () { 211 | /**************************************************************************************** 212 | * Enums 213 | ****************************************************************************************/ 214 | const FilterTechniqueEnum = { 215 | NO_FILTER: 0, 216 | MEDIAN_1D: 1, 217 | 218 | properties: { 219 | 0: { name: "NO_FILTER", value: 0, parameterDefaultKey: 'NO_FILTER', displayName: "No Filter", bIsDefault: true }, 220 | 1: { name: "MEDIAN_1D", value: 1, parameterDefaultKey: 'MEDIAN_1D', displayName: "Median 1D", bIsDefault: false } 221 | } 222 | }; 223 | 224 | /**************************************************************************************** 225 | * Defaults for various types of classes 226 | ****************************************************************************************/ 227 | const FilterParameterDefaults = { 228 | NO_FILTER: { 229 | 230 | }, 231 | MEDIAN_1D: { 232 | bPadBoundaries: false, // True-> assume discontiguous readings, False-> assume contiguous readings 233 | windowSize: 3 234 | } 235 | }; 236 | 237 | /**************************************************************************************** 238 | * Methods 239 | ****************************************************************************************/ 240 | // verifies an odd filter size >= 3 241 | let _checkFilterSize = (filterSize) => { 242 | // if the filter is too small, make it 3 243 | if (filterSize < 3) 244 | return 3; 245 | // if the filter is even sized, make it odd 246 | if ((filterSize % 2) === 0) 247 | return filterSize - 1; 248 | return filterSize; 249 | }; 250 | 251 | // performs a 1D median filter on the input sensor readings 252 | // returns an array of sensor readings (filtered) 253 | let medianFilter1D = (sensorReadings, params) => { 254 | let filterType = FilterTechniqueEnum.MEDIAN_1D; 255 | let defaultParams = FilterParameterDefaults[FilterTechniqueEnum.properties[filterType].parameterDefaultKey]; 256 | params = (typeof params === 'undefined' || !params) ? defaultParams : _HELPERS.checkParams(params, defaultParams); 257 | 258 | // example: 259 | // len=9 260 | // k=5 (sliding window is 5 elements wide) 261 | // offset=2 (a sliding window of size 5 has 2 spaces to either side of its center) 262 | // firstOverlapIndex=2 263 | // lastOverlapIndex=6 264 | let len = sensorReadings.length; 265 | // Guarantee that the size of the sliding window is odd and >=3 266 | let k = _checkFilterSize(params.windowSize); 267 | // The number of spaces to either side of the center of the sliding window 268 | let offset = Math.floor(k / 2); 269 | // The first index where the sliding window is completely overlapping the sensorReadings array 270 | let firstOverlapIndex = offset; 271 | // The last index where the sliding window is completely overlapping the sensorReadings array 272 | let lastOverlapIndex = len - offset - 1; 273 | 274 | if (len < k) 275 | return sensorReadings; 276 | 277 | 278 | let filteredReadings = []; 279 | let window; 280 | 281 | // handle array indices where the left side of the sliding window is not yet overlapping the array 282 | for (let i = 0; i < firstOverlapIndex; i++) { 283 | window = []; 284 | 285 | // fill the portion of window that is NOT overlapping 286 | for (let j = i - offset; j < 0; j++) { 287 | window.push(params.bPadBoundaries ? 288 | sensorReadings[0] : // pad the missing elements with the value at index 0 289 | sensorReadings[len + j] // or assume array is contiguous/circular and pull values from the high indices 290 | ); 291 | } 292 | // fill the portion of the window that IS overlapping the sensor readings array 293 | for (let j = 0; j <= i + offset; j++) 294 | window.push(sensorReadings[j]); 295 | 296 | let newSensorReading = new _DATA.SensorReading( 297 | sensorReadings[i].polarCoord.angle, 298 | SensorReadingUtils.findMedianRadius(window, offset), 299 | sensorReadings[i].signalStrength); 300 | 301 | filteredReadings.push(newSensorReading); 302 | } 303 | // handle the array indices where the entire sliding window is overlapping the array 304 | for (let i = offset; i <= lastOverlapIndex; i++) { 305 | window = []; 306 | for (let j = i - offset; j <= i + offset; j++) 307 | window.push(sensorReadings[j]); 308 | 309 | let newSensorReading = new _DATA.SensorReading( 310 | sensorReadings[i].polarCoord.angle, 311 | SensorReadingUtils.findMedianRadius(window, offset), 312 | sensorReadings[i].signalStrength); 313 | 314 | filteredReadings.push(newSensorReading); 315 | } 316 | // handle array indices where the right side of the sliding window is not overlapping the array 317 | for (let i = lastOverlapIndex + 1; i < len; i++) { 318 | window = []; 319 | // fill the portion of the window that IS overlapping the sensor readings array 320 | for (let j = i - offset; j < len; j++) 321 | window.push(sensorReadings[j]); 322 | //fill the portion of window that is NOT overlapping 323 | for (let j = len; j <= i + offset; j++) { 324 | window.push(params.bPadBoundaries ? 325 | sensorReadings[len - 1] : // pad the missing elements with the value at index (len-1) 326 | sensorReadings[j - len] // or assume array is contiguous/circular and pull values from the early indices 327 | ); 328 | } 329 | 330 | let newSensorReading = new _DATA.SensorReading( 331 | sensorReadings[i].polarCoord.angle, 332 | SensorReadingUtils.findMedianRadius(window, offset), 333 | sensorReadings[i].signalStrength); 334 | 335 | filteredReadings.push(newSensorReading); 336 | } 337 | return filteredReadings; 338 | }; 339 | 340 | /************************************************************************************//** 341 | ** Public API --- filtering sub-module 342 | * Return all the methods/variables that should be public. 343 | ****************************************************************************************/ 344 | return { 345 | // Public enums 346 | FilterTechniqueEnum: FilterTechniqueEnum, 347 | FilterParameterDefaults: FilterParameterDefaults, 348 | 349 | // Public methods 350 | medianFilter1D: medianFilter1D, 351 | }; 352 | }(); 353 | 354 | 355 | /************************************************************************************//** 356 | ** Public API --- processing module 357 | * Return all the methods/variables that should be public. 358 | ****************************************************************************************/ 359 | return { 360 | // Public sub-modules 361 | Point2DUtils: Point2DUtils, 362 | SensorReadingUtils: SensorReadingUtils, 363 | Filtering: Filtering 364 | }; 365 | }(); -------------------------------------------------------------------------------- /examples/line_extraction/js/components/Utils.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************//** 2 | ** Utils (Module): LineExtractionApp module. 3 | * Contains helpful classes and methods 4 | ****************************************************************************************/ 5 | LineExtractionApp.Utils = function () { 6 | 7 | /**************************************************************************************** 8 | * Sub-Modules 9 | ****************************************************************************************/ 10 | 11 | /************************************************************************************//** 12 | ** GenericHelpers (Module): 13 | * Provides generic helper functions useful to other modules. 14 | ****************************************************************************************/ 15 | let GenericHelpers = function () { 16 | 17 | /**************************************************************************************** 18 | * Methods 19 | ****************************************************************************************/ 20 | //creates an array of length "len" and filled with the specified itm value 21 | var createPopulatedArray = function (len, itm) { 22 | var arr1 = [itm], 23 | arr2 = []; 24 | while (len > 0) { 25 | if (len & 1) 26 | arr2 = arr2.concat(arr1); 27 | arr1 = arr1.concat(arr1); 28 | len >>>= 1; 29 | } 30 | return arr2; 31 | }; 32 | 33 | //Returns the default value of any enum with a properties list containing a default parameter 34 | var getEnumDefault = function (theEnum) { 35 | for (let key in theEnum) { 36 | //don't consider the properties key 37 | if (key === 'properties') 38 | break; 39 | if (theEnum.properties[theEnum[key]].bIsDefault) { 40 | return theEnum[key]; 41 | } 42 | } 43 | return null; 44 | }; 45 | 46 | // compares a parameter object to its default, adding in any missed parameters using default values 47 | var checkParams = function (params, defaults) { 48 | if (!params) 49 | return defaults; 50 | 51 | let merged = {}; 52 | // check each parameter in the defaults object 53 | for (let key in defaults) { 54 | // make sure the parameter key doesn't come from the prototype 55 | if (!defaults.hasOwnProperty(key)) 56 | continue; 57 | if (!params.hasOwnProperty(key)) { 58 | // if the params object is missing a necessary key, 59 | // pull its default from the defaults object 60 | merged[key] = defaults[key]; 61 | } 62 | else { 63 | // otherwise, use the one from the params object 64 | merged[key] = params[key]; 65 | } 66 | } 67 | return merged; 68 | }; 69 | 70 | /************************************************************************************//** 71 | ** Public API 72 | * Return all the methods/variables that should be public. 73 | ****************************************************************************************/ 74 | return { 75 | // public methods 76 | createPopulatedArray: createPopulatedArray, 77 | getEnumDefault: getEnumDefault, 78 | checkParams: checkParams 79 | }; 80 | }(); 81 | 82 | /************************************************************************************//** 83 | ** Public API 84 | * Return all the methods/variables that should be public. 85 | ****************************************************************************************/ 86 | return { 87 | // public sub-modules 88 | GenericHelpers: GenericHelpers 89 | }; 90 | }(); -------------------------------------------------------------------------------- /examples/line_extraction/js/main.js: -------------------------------------------------------------------------------- 1 | /**************************************************************************************** 2 | * Module Includes 3 | ****************************************************************************************/ 4 | const _EVENTS = LineExtractionApp.EventDispatcher; 5 | const _DATA = LineExtractionApp.Data; 6 | const _PLOTTING = LineExtractionApp.Plotting; 7 | const _GRAPHICS = LineExtractionApp.Graphics; 8 | 9 | /**************************************************************************************** 10 | * Global Variables 11 | ****************************************************************************************/ 12 | let graphManager = new _PLOTTING.GraphManager(); 13 | let visualizer = new _GRAPHICS.Visualizer(); 14 | let dataPlayback = new _DATA.DataPlayback(); 15 | 16 | /**************************************************************************************** 17 | * Methods 18 | ****************************************************************************************/ 19 | // Once the document is ready, initialize various components of the application 20 | $(document).ready(function () { 21 | // init components 22 | initializeGraphManager(); 23 | initializeVisualizer(); 24 | initCustomEventSubscriptions(); 25 | 26 | // begin playback 27 | playbackData(); 28 | }); 29 | 30 | function initializeGraphManager() { 31 | graphManager.init('div_Cartesian_Plot_Container', 'div_Polar_Plot_Container'); 32 | } 33 | 34 | function initializeVisualizer() { 35 | visualizer.init('div_Visualizer_Container'); 36 | visualizer.animate(); 37 | } 38 | 39 | function playbackData() { 40 | let jsonObject = JSON.parse(EXAMPLE_RECORDING_1_JSON_DATA); 41 | let recordingData = _DATA.ScanFile.interpretJSONData(jsonObject); 42 | dataPlayback.init(recordingData); 43 | dataPlayback.cycle(); 44 | } 45 | 46 | function initCustomEventSubscriptions() { 47 | // Draw a scan whenever the event fires 48 | _EVENTS.subscribe('event_CollectedCompleteScanData', function (scanData) { 49 | visualizer.drawSingleScan(scanData); 50 | graphManager.update(scanData); 51 | }); 52 | } 53 | 54 | -------------------------------------------------------------------------------- /examples/line_extraction/js/namespace.js: -------------------------------------------------------------------------------- 1 | // create the root namespace and making sure we're not overwriting it 2 | var LineExtractionApp = {}; 3 | 4 | /************************************************************************************//** 5 | ** General purpose namespace method. 6 | ** This will allow us to create namespace a bit easier. 7 | ****************************************************************************************/ 8 | LineExtractionApp.createNameSpace = function (namespace) { 9 | let nsparts = namespace.split("."); 10 | let parent = LineExtractionApp; 11 | 12 | // we want to be able to include or exclude the root namespace 13 | // So we strip it if it's in the namespace 14 | if (nsparts[0] === "LineExtractionApp") { 15 | nsparts = nsparts.slice(1); 16 | } 17 | 18 | // loop through the parts and create 19 | // a nested namespace if necessary 20 | for (let i = 0; i < nsparts.length; i++) { 21 | let partname = nsparts[i]; 22 | // check if the current parent already has 23 | // the namespace declared, if not create it 24 | if (typeof parent[partname] === "undefined") { 25 | parent[partname] = {}; 26 | } 27 | // get a reference to the deepest element 28 | // in the hierarchy so far 29 | parent = parent[partname]; 30 | } 31 | // the parent is now completely constructed 32 | // with empty namespaces and can be used. 33 | return parent; 34 | }; 35 | 36 | 37 | /************************************************************************************//** 38 | ** Create various namespaces for the app 39 | ****************************************************************************************/ 40 | LineExtractionApp.createNameSpace("LineExtractionApp.EventDispatcher"); 41 | LineExtractionApp.createNameSpace("LineExtractionApp.Utils"); 42 | LineExtractionApp.createNameSpace("LineExtractionApp.Data"); 43 | LineExtractionApp.createNameSpace("LineExtractionApp.Processing"); 44 | LineExtractionApp.createNameSpace("LineExtractionApp.Perception"); 45 | LineExtractionApp.createNameSpace("LineExtractionApp.Plotter"); 46 | LineExtractionApp.createNameSpace("LineExtractionApp.Graphics"); -------------------------------------------------------------------------------- /examples/line_extraction/style/style-helper-utils.css: -------------------------------------------------------------------------------- 1 | .visualizer-vertical-space-fill { 2 | height: -webkit-calc(100vh - 175px); 3 | height: -moz-calc(100vh - 175px); 4 | height: calc(100vh - 175px); 5 | } --------------------------------------------------------------------------------