├── .bowerrc ├── .dockerignore ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .travis.yml ├── Dockerfile ├── Gruntfile.js ├── LICENSE ├── README.md ├── app ├── .buildignore ├── .htaccess ├── 404.html ├── data │ └── drivemap.json ├── favicon.ico ├── images │ ├── icons │ │ ├── backtodrivemap_icon_80px.png │ │ ├── backtodrivemap_icon_green_80px.png │ │ ├── extract_icon_80px.png │ │ ├── extract_icon_green_80px.png │ │ ├── gear_icon_80px.png │ │ ├── gear_icon_80px_hd.png │ │ ├── gear_icon_80px_ld.png │ │ ├── gear_icon_80px_md.png │ │ ├── gear_icon_80px_sd.png │ │ ├── gear_icon_green_80px.png │ │ ├── gear_icon_green_80px_hd.png │ │ ├── gear_icon_green_80px_ld.png │ │ ├── gear_icon_green_80px_md.png │ │ ├── gear_icon_green_80px_sd.png │ │ ├── heli_icon_80px.png │ │ ├── heli_icon_green_80px.png │ │ ├── help_icon_80px.png │ │ ├── help_icon_green_80px.png │ │ ├── indy_icon_80px.png │ │ ├── indy_icon_green_80px.png │ │ ├── new │ │ │ ├── gear_icon_80px.pdn │ │ │ └── gear_icon__green_80px.pdn │ │ ├── person_icon_80px.png │ │ ├── person_icon_green_80px.png │ │ ├── play_icon_80px.png │ │ ├── play_icon_green_80px.png │ │ ├── toolbox_angle_icon_50px.png │ │ ├── toolbox_angle_icon_green_50px.png │ │ ├── toolbox_area_icon_50px.png │ │ ├── toolbox_area_icon_green_50px.png │ │ ├── toolbox_bottom_icon_green_80px.png │ │ ├── toolbox_clipvolume_icon_50px.png │ │ ├── toolbox_clipvolume_icon_green_50px.png │ │ ├── toolbox_distance_icon_50px.png │ │ ├── toolbox_distance_icon_green_50px.png │ │ ├── toolbox_heightprofile_icon_50px.png │ │ ├── toolbox_heightprofile_icon_green_50px.png │ │ ├── toolbox_icon_80px.png │ │ ├── toolbox_move_icon_30px.png │ │ ├── toolbox_move_icon_green_30px.png │ │ ├── toolbox_rotation_icon_30px.png │ │ ├── toolbox_rotation_icon_green_30px.png │ │ ├── toolbox_scale_icon_30px.png │ │ ├── toolbox_scale_icon_green_30px.png │ │ ├── toolbox_top_icon_green_80px.png │ │ ├── toolbox_trash_icon_50px.png │ │ ├── toolbox_trash_icon_green_50px.png │ │ ├── toolbox_volume_icon_50px.png │ │ └── toolbox_volume_icon_green_50px.png │ ├── logos │ │ ├── ahn.png │ │ ├── ahn_inv.pdn │ │ ├── ahn_inv.png │ │ ├── nlesc.png │ │ ├── nlesc_inv.png │ │ ├── potree.jpg │ │ ├── potree_logo.pdn │ │ ├── potree_logo.png │ │ ├── tudelft.png │ │ └── tudelft_inv.png │ ├── rainbow_colormap.png │ └── skybox │ │ ├── nx.jpg │ │ ├── ny.jpg │ │ ├── nz.jpg │ │ ├── px.jpg │ │ ├── py.jpg │ │ └── pz.jpg ├── index.html ├── robots.txt ├── scripts │ ├── app.js │ ├── biglegend │ │ ├── biglegend.controller.js │ │ ├── biglegend.directive.html │ │ └── biglegend.directive.js │ ├── core │ │ ├── constants.js │ │ └── drivemap.service.js │ ├── earthcontrols │ │ ├── earthcontrols.controller.js │ │ ├── earthcontrols.directive.html │ │ ├── earthcontrols.directive.js │ │ └── earthcontrols.service.js │ ├── extract │ │ ├── extraction.controller.js │ │ ├── extraction.directive.html │ │ ├── extraction.directive.js │ │ ├── extraction.selection.service.js │ │ ├── minimap.extraction.selection.service.js │ │ ├── pointcloud.extraction.drawing.service.js │ │ └── pointcloud.extraction.selection.service.js │ ├── help │ │ ├── help.controller.js │ │ ├── help.directive.html │ │ └── help.directive.js │ ├── helpModal │ │ ├── helpModal.controller.js │ │ ├── helpModal.directive.html │ │ └── helpModal.directive.js │ ├── logos │ │ ├── logos.directive.html │ │ └── logos.directive.js │ ├── measuring │ │ ├── measuring.controller.js │ │ ├── measuring.directive.html │ │ ├── measuring.directive.js │ │ └── measuring.service.js │ ├── minimap │ │ ├── cam-frustum.service.js │ │ ├── minimap.controller.js │ │ └── minimap.directive.js │ ├── pointcloud │ │ ├── camera.service.js │ │ ├── gradients.service.js │ │ ├── path.controls.js │ │ ├── pointcloud-canvas.controller.js │ │ ├── pointcloud-canvas.directive.js │ │ ├── pointcloud-stats.controller.js │ │ ├── pointcloud-stats.directive.html │ │ ├── pointcloud-stats.directive.js │ │ ├── pointcloud.service.js │ │ ├── rail.service.js │ │ └── scene.service.js │ ├── searchbox │ │ ├── searchbox.controller.js │ │ ├── searchbox.directive.html │ │ └── searchbox.directive.js │ ├── settings │ │ ├── settings.controller.js │ │ ├── settings.directive.html │ │ └── settings.directive.js │ └── utils │ │ ├── MeasuringTool.js │ │ ├── TextSprite.js │ │ ├── binggeocoder.service.js │ │ ├── decimaladjust.service.js │ │ ├── messagebus.service.js │ │ ├── startfrom.filter.js │ │ └── userAgent.service.js └── styles │ └── main.scss ├── bower.json ├── doc └── ahn2-screenshot.png ├── e2e ├── e2e-local.conf.js ├── e2e-sauce.conf.js └── scenario.js ├── package-lock.json ├── package.json └── test ├── .jshintrc ├── karma.conf.js ├── karma.conf.windows.js ├── mock ├── demoWaypoints.js └── drivemap.js ├── polyfills ├── Blob.js ├── canvas.webgl.js └── string.includes.js └── spec ├── app.spec.js ├── core ├── constants.spec.js └── drivemap.service.spec.js ├── earthcontrols ├── earth.controls.controller.spec.js ├── earth.controls.directive.spec.js └── earth.controls.service.spec.js ├── extract ├── extraction.controller.spec.js ├── extraction.directive.spec.js ├── extraction.selection.service.spec.js └── minimap-extraction-selection.service.spec.js ├── help └── help.directive.spec.js ├── measuring └── measuring.spec.js ├── minimap ├── cam-frustum.service.spec.js ├── minimap.controller.spec.js └── minimap.directive.spec.js ├── pointcloud ├── camera.service.spec.js ├── constants.spec.js ├── pointcloud-canvas.controller.spec.js ├── pointcloud-canvas.directive.spec.js ├── pointcloud-stats.directive.spec.js ├── pointcloud.service.spec.js ├── rail.service.spec.js └── scene.service.spec.js ├── searchbox ├── searchbox.controller.spec.js └── searchbox.directive.spec.js ├── settings ├── settings.controller.spec.js └── settings.directive.spec.js └── utils ├── binggeocoder.services.spec.js ├── messagebus.service.spec.js └── startfrom.filter.spec.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | charset = utf-8 12 | 13 | # Matches multiple files with brace expansion notation 14 | # Set default charset 15 | [*.{js,py,java,r,R}] 16 | indent_style = space 17 | 18 | # 4 space indentation 19 | [*.py] 20 | indent_size = 4 21 | 22 | # Tab indentation (no size specified) 23 | [*.js] 24 | indent_size = 2 25 | 26 | # Matches the exact files either package.json or .travis.yml 27 | [*.{json,yml}] 28 | indent_size = 2 29 | 30 | [*.{md,Rmd}] 31 | trim_trailing_whitespace = false 32 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .tmp 4 | .sass-cache 5 | .project 6 | bower_components 7 | app/data/out_8 8 | test/reports 9 | e2e/reports 10 | 11 | ## Non-project files: 12 | # exvim 13 | .exvim.project* 14 | project.exvim 15 | 16 | /npm-debug.log 17 | 18 | .grunt 19 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "globals": { 21 | "angular": false 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '6' 4 | addons: 5 | sauce_connect: true 6 | code_climate: 7 | repo_token: d92e680b8632754fe9b7dea8ec25b9a59f72804e226a171ca4b0a95b12f438e9 8 | before_install: 9 | - gem install compass 10 | install: 11 | - 'npm install -g npm@2' 12 | - 'npm install' 13 | - 'npm install -g bower grunt-cli' 14 | - 'bower install' 15 | script: 16 | - 'grunt test' 17 | - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && grunt e2e-sauce --verbose || false' 18 | after_script: 19 | - codeclimate < test/reports/coverage/*/lcov.info 20 | env: 21 | global: 22 | - secure: BrEVqXCOV40SehtQRfj5jyjS0oaxm5GkDENgkqYfSK7x3Y/DY+R0oV5dgQOx+AefyOi3VGXsMEQ9I9QdxoHEVvieWLzkYVqCvucte+gjtxI9cdKEpfrdwWZINr3JszniXdPpY47ImrB24rciUwE2Lrn6B/q22+/kfJjO5goMGdi1mdhPT/d3nb/bm+81FeW+z2AlA2VdJB/zaJvNO7fbYgBCHdo5vFoXh3PQ79MF1icADuvMttn8qfg5Ge45lcHSZORLaZ/hhQCdubWPhjYKtNCavyMDy9hDHKtKqsB0o0iBKGJWIJkiYe8rVc9oDxSzftOwcOv7FpPhSvUDZUc9x0alxmJ2v21Q6Epn/YhZJhQFxsbjHQPy3vUlb6obgJ4ZQy/tPIwChOM3judF/vtxSRcdsGDaD/fUY9p37xzd6lG330xWgKxKOHn536kpzI+1/7NMWRF1QM6gjP6tjMjMHCng7CnKAFzzyldJiZA8AltXZoa+g3dVJn7uJK0vILyALlq3UPTDmcQzzrudlrqTrNoY5oNL+MNpcafmBlXndSPQ3X86Y7BKnYHRZQM4X1o90O3HWUbJ4dUscPhbmKgwDTELvPgYYcADAG+0UV/0ZziHrw+BKg98Mx15eyr2W0Za5cjSEH7UHUl1qt7vIB3Vjis7sCGZG7g2ILUgnp4I6SE= 23 | - secure: HzLFrTR0u/kUxPIhAnCh/z7uUcy38tFLbut7gBXfHr2E0iBOWJducPG3IrPkccRz/9aidZAYFmtNXzw536cXWpLM0rnd/jYRfY72tghNgZkAlvaajyw5ajDM4d6ur0iC5Fhjwz/1rdKnFbu3+9xNHKtb2wldi5AUTG/3cummdS+mhYMVhL3iChltRWTUhvsNRjEBDvhfYM/2f9S9AS69PcU5nRKxGWf2j43rVKtlGA/WHX1TcggnDiXdc0Ap7GzJFsdB+Aqe54eXFnuDPZEOz8DjnogQ82/mxug0LwTZrmhbxbG7QJi3RxhiQSfxEDPVRVrVU5H1kqBOkl4SS2W2Qd/QYTVBakh5s6BuAxYTY+lmqyMm3d97T0U76KXciOwt6fo29oCEHEsb+Cp+RD8R/iesIwyovTIVus9ujxzSkepnrCTg2ERPTm4B6ycPJIxK2QmPEBXHjEDATjSP0FLEbw9GVZ70uXUNGKgN/Ib6DQb32CKIWOtDCzy2WGI2eMM/lpql6nUU6pof9EqgNCxrP19gv2MdBWs2z4pLWirc6dZdf86RNlpsK1DMF+pu2h5m48NT6glllFEP9LozdaPafDH2PJOjf5azCmSHrSM2zlo0Axhvu6Z4y5oJ35148ST1SjtLcKlPsuwWNDkeRZgmckOyCvOJxekaanc0Zpxql98= 24 | sudo: false 25 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | MAINTAINER Maarten van Meersbergen 4 | RUN apt-get update -y 5 | 6 | RUN apt-get install locales -y 7 | 8 | RUN locale-gen en_US.UTF-8 9 | ENV LC_ALL=en_US.UTF-8 10 | ENV LANG=en_US.UTF-8 11 | 12 | RUN apt-get install build-essential -y 13 | 14 | RUN apt-get install git -y 15 | RUN apt-get install curl -y 16 | RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - 17 | RUN apt-get install -y nodejs 18 | 19 | ADD . /app 20 | WORKDIR /app 21 | 22 | RUN npm install -g bower grunt-cli 23 | 24 | RUN apt-get install ruby-dev libffi-dev -y 25 | RUN gem install compass 26 | 27 | RUN npm install 28 | RUN bower install --allow-root 29 | 30 | EXPOSE 9000 31 | 32 | CMD grunt serve --force 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AHN2 point cloud viewer 2 | ===================== 3 | 4 | [![Build Status](https://travis-ci.org/NLeSC/ahn-pointcloud-viewer.svg)](https://travis-ci.org/NLeSC/ahn-pointcloud-viewer) 5 | [![Code Climate](https://codeclimate.com/github/NLeSC/ahn-pointcloud-viewer/badges/gpa.svg)](https://codeclimate.com/github/NLeSC/ahn-pointcloud-viewer) 6 | [![Test Coverage](https://codeclimate.com/github/NLeSC/ahn-pointcloud-viewer/badges/coverage.svg)](https://codeclimate.com/github/NLeSC/ahn-pointcloud-viewer/coverage) 7 | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.910448.svg)](https://doi.org/10.5281/zenodo.910448) 8 | 9 | Point cloud visualization of the current digital elevation model of the Netherlands ([Actueel Hoogtebestand Nederland or AHN2](http://www.ahn.nl/)). For further details, please refer to the publication by [Martinez-Rubi _et al._ (2015)](http://dx.doi.org/10.13140/RG.2.1.1731.4326/1). 10 | 11 | ![Willemstad in the AHN2 viewer](/doc/ahn2-screenshot.png "screenshot of ahn2 viewer showing willemstad") 12 | 13 | Related repositories 14 | -------------------- 15 | 16 | - [Massive-PotreeConverter](https://github.com/NLeSC/Massive-PotreeConverter) extends the [PotreeConverter](https://github.com/potree/PotreeConverter) to handle massive point cloud data such as AHN2. 17 | - [ahn-pointcloud-viewer-ws](https://github.com/NLeSC/ahn-pointcloud-viewer-ws) corresponds to a RESTful web service that enables communication between this web application (viewer) and database of point cloud (meta)data. 18 | 19 | 20 | Prerequisites 21 | ------------- 22 | 23 | * Point cloud data in the _potree_ format 24 | * [Node.js](http://nodejs.org/) 25 | * [Bower](http://bower.io) 26 | * [Compass](http://compass-style.org) 27 | * [Java Development Kit](https://www.java.com/) 28 | * Supported web browsers: 29 | * [Google Chrome](https://www.google.com/chrome/) 30 | * [Microsoft Edge](http://www.microsoft.com/en-us/windows/microsoft-edge) 31 | 32 | Installation: Windows 33 | --------------------- 34 | 35 | ### Install [Git CLI/GUI clients](http://git-scm.com/downloads) 36 | 37 | ### Install [Node.js](http://nodejs.org/) and required modules 38 | 39 | * Make sure the _Add node to PATH_ option is checked. 40 | * Create '$HOME/npm' folder (where $HOME is C:\Users\\AppData\Roaming). 41 | 42 | `npm install -g bower grunt-cli` 43 | 44 | ### Install [Ruby](http://rubyinstaller.org/) and required package 45 | 46 | * Make sure the _Add Ruby to PATH_ option is checked 47 | 48 | `gem install compass` 49 | 50 | ### Install AHN2 viewer 51 | 52 | ``` 53 | git clone https://github.com/NLeSC/ahn-pointcloud-viewer 54 | cd ahn-pointcloud-viewer 55 | npm install -g grunt grunt-cli 56 | npm install 57 | bower install 58 | bower update 59 | ``` 60 | 61 | ### Test AHN2 viewer 62 | 63 | ``` 64 | grunt serve # starts the web server and opens http://localhost:9000 in your browser 65 | ``` 66 | 67 | 68 | Installation: Debian/Ubuntu-based Linux distros 69 | ----------------------------------------------- 70 | 71 | ### Install Node.js and required modules 72 | 73 | See the documentation [here](https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions). 74 | 75 | ``` 76 | curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - 77 | sudo apt-get install -y nodejs 78 | sudo npm install -g bower grunt-cli 79 | ``` 80 | 81 | ### Install Ruby and required package 82 | 83 | ``` 84 | sudo apt-get install ruby-dev libffi-dev build-essential 85 | sudo gem install compass 86 | ``` 87 | 88 | ### Install AHN2 viewer 89 | 90 | ``` 91 | git clone https://github.com/NLeSC/ahn-pointcloud-viewer 92 | cd ahn-pointcloud-viewer 93 | npm install phantomjs 94 | npm install 95 | bower install 96 | #bower update 97 | ``` 98 | 99 | ### Test AHN2 viewer 100 | 101 | ``` 102 | grunt serve # starts the web server and opens http://localhost:9000 in your browser 103 | ``` 104 | 105 | ### Run unit tests 106 | 107 | ``` 108 | grunt test 109 | ``` 110 | 111 | Note: This generates test and coverage reports (see the `test/reports` folder). 112 | 113 | ### Run end-to-end tests locally 114 | 115 | ``` 116 | grunt e2e-local 117 | ``` 118 | 119 | Note: Both the point cloud and minimap use a canvas and can't be tested automatically so they must be verified manually using the screenshots in the report (open `e2e/reports/report.html` in your browser). 120 | 121 | ### Run end-to-end tests remotely on [Sauce Labs](https://saucelabs.com/) 122 | 123 | Connect to Sauce Labs using the sauce-connect program. Further details on how to install and run this tool can be found [here](https://docs.saucelabs.com/reference/sauce-connect/). 124 | 125 | Setup Sauce Labs credentials before running the tests. 126 | 127 | ``` 128 | export SAUCE_USERNAME= 129 | export SAUCE_ACCESS_KEY= 130 | ``` 131 | 132 | Run the tests in Google Chrome (Linux). 133 | 134 | ``` 135 | grunt e2e-sauce 136 | ``` 137 | 138 | Both the point cloud window and minimap use a canvas, which can't be tested automatically. Therefore, the tests must be verified manually using the screencast in the report at `https://saucelabs.com/u/`. 139 | 140 | Also Travis-CI runs end-to-end tests on Sauce Labs. 141 | 142 | Note: Executing `grunt e2e-sauce` locally will undo all changes in `app/` folder. 143 | 144 | ### Build a distro 145 | 146 | ``` 147 | grunt build 148 | ``` 149 | The `dist` folder has production ready distribution. 150 | 151 | ### Generate API documentation 152 | 153 | ``` 154 | grunt jsdoc 155 | ``` 156 | 157 | API documentation is generated in `doc/` directory. 158 | 159 | Frame rate report 160 | ---------------- 161 | 162 | Use Chrome FPS plotting to get the frame rate. 163 | 1. Open developer tools 164 | 2. On Console tab goto Rendering tab (bottom screen) 165 | 3. Check the Show FPS meter checkbox 166 | 167 | ### Deploy to GitHub pages 168 | 169 | Deploy distribution to `gh-pages` branch. 170 | Make it available as http://nlesc.github.io/ahn-pointcloud-viewer 171 | 172 | ``` 173 | grunt build 174 | grunt gh-pages 175 | ``` 176 | -------------------------------------------------------------------------------- /app/.buildignore: -------------------------------------------------------------------------------- 1 | *.coffee -------------------------------------------------------------------------------- /app/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |

Sorry, but the page you were trying to view does not exist.

146 |

It looks like this was the result of either:

147 |
    148 |
  • a mistyped address
  • 149 |
  • an out-of-date link
  • 150 |
151 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /app/data/drivemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [{ 4 | "type": "Feature", 5 | "geometry": { 6 | "type": "LineString", 7 | "coordinates": [ 8 | [140183.36973145982,351353.9722696242,80588.82034192003], 9 | [140094.3457301586,352113.56990427256,79971.3224536391] 10 | ] 11 | }, 12 | "properties": { 13 | "pointcloud": "http://ahn2.pointclouds.nl//potree_data/tile_all/cloud.js", 14 | "proj4": "+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +units=m +no_defs", 15 | "lookatpath": [ 16 | [140182.68295567224,351359.832186682,80580.74632736137], 17 | [140093.658954371,352119.42982133036,79963.24843908045] 18 | ] 19 | }, 20 | "id": "DRIVE_1_V3" 21 | }], 22 | 23 | "crs": { 24 | "type": "name", 25 | "properties": { 26 | "name": "urn:ogc:def:crs:EPSG::28992" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/favicon.ico -------------------------------------------------------------------------------- /app/images/icons/backtodrivemap_icon_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/backtodrivemap_icon_80px.png -------------------------------------------------------------------------------- /app/images/icons/backtodrivemap_icon_green_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/backtodrivemap_icon_green_80px.png -------------------------------------------------------------------------------- /app/images/icons/extract_icon_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/extract_icon_80px.png -------------------------------------------------------------------------------- /app/images/icons/extract_icon_green_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/extract_icon_green_80px.png -------------------------------------------------------------------------------- /app/images/icons/gear_icon_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/gear_icon_80px.png -------------------------------------------------------------------------------- /app/images/icons/gear_icon_80px_hd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/gear_icon_80px_hd.png -------------------------------------------------------------------------------- /app/images/icons/gear_icon_80px_ld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/gear_icon_80px_ld.png -------------------------------------------------------------------------------- /app/images/icons/gear_icon_80px_md.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/gear_icon_80px_md.png -------------------------------------------------------------------------------- /app/images/icons/gear_icon_80px_sd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/gear_icon_80px_sd.png -------------------------------------------------------------------------------- /app/images/icons/gear_icon_green_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/gear_icon_green_80px.png -------------------------------------------------------------------------------- /app/images/icons/gear_icon_green_80px_hd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/gear_icon_green_80px_hd.png -------------------------------------------------------------------------------- /app/images/icons/gear_icon_green_80px_ld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/gear_icon_green_80px_ld.png -------------------------------------------------------------------------------- /app/images/icons/gear_icon_green_80px_md.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/gear_icon_green_80px_md.png -------------------------------------------------------------------------------- /app/images/icons/gear_icon_green_80px_sd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/gear_icon_green_80px_sd.png -------------------------------------------------------------------------------- /app/images/icons/heli_icon_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/heli_icon_80px.png -------------------------------------------------------------------------------- /app/images/icons/heli_icon_green_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/heli_icon_green_80px.png -------------------------------------------------------------------------------- /app/images/icons/help_icon_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/help_icon_80px.png -------------------------------------------------------------------------------- /app/images/icons/help_icon_green_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/help_icon_green_80px.png -------------------------------------------------------------------------------- /app/images/icons/indy_icon_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/indy_icon_80px.png -------------------------------------------------------------------------------- /app/images/icons/indy_icon_green_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/indy_icon_green_80px.png -------------------------------------------------------------------------------- /app/images/icons/new/gear_icon_80px.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/new/gear_icon_80px.pdn -------------------------------------------------------------------------------- /app/images/icons/new/gear_icon__green_80px.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/new/gear_icon__green_80px.pdn -------------------------------------------------------------------------------- /app/images/icons/person_icon_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/person_icon_80px.png -------------------------------------------------------------------------------- /app/images/icons/person_icon_green_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/person_icon_green_80px.png -------------------------------------------------------------------------------- /app/images/icons/play_icon_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/play_icon_80px.png -------------------------------------------------------------------------------- /app/images/icons/play_icon_green_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/play_icon_green_80px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_angle_icon_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_angle_icon_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_angle_icon_green_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_angle_icon_green_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_area_icon_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_area_icon_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_area_icon_green_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_area_icon_green_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_bottom_icon_green_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_bottom_icon_green_80px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_clipvolume_icon_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_clipvolume_icon_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_clipvolume_icon_green_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_clipvolume_icon_green_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_distance_icon_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_distance_icon_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_distance_icon_green_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_distance_icon_green_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_heightprofile_icon_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_heightprofile_icon_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_heightprofile_icon_green_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_heightprofile_icon_green_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_icon_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_icon_80px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_move_icon_30px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_move_icon_30px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_move_icon_green_30px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_move_icon_green_30px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_rotation_icon_30px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_rotation_icon_30px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_rotation_icon_green_30px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_rotation_icon_green_30px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_scale_icon_30px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_scale_icon_30px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_scale_icon_green_30px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_scale_icon_green_30px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_top_icon_green_80px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_top_icon_green_80px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_trash_icon_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_trash_icon_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_trash_icon_green_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_trash_icon_green_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_volume_icon_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_volume_icon_50px.png -------------------------------------------------------------------------------- /app/images/icons/toolbox_volume_icon_green_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/icons/toolbox_volume_icon_green_50px.png -------------------------------------------------------------------------------- /app/images/logos/ahn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/logos/ahn.png -------------------------------------------------------------------------------- /app/images/logos/ahn_inv.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/logos/ahn_inv.pdn -------------------------------------------------------------------------------- /app/images/logos/ahn_inv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/logos/ahn_inv.png -------------------------------------------------------------------------------- /app/images/logos/nlesc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/logos/nlesc.png -------------------------------------------------------------------------------- /app/images/logos/nlesc_inv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/logos/nlesc_inv.png -------------------------------------------------------------------------------- /app/images/logos/potree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/logos/potree.jpg -------------------------------------------------------------------------------- /app/images/logos/potree_logo.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/logos/potree_logo.pdn -------------------------------------------------------------------------------- /app/images/logos/potree_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/logos/potree_logo.png -------------------------------------------------------------------------------- /app/images/logos/tudelft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/logos/tudelft.png -------------------------------------------------------------------------------- /app/images/logos/tudelft_inv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/logos/tudelft_inv.png -------------------------------------------------------------------------------- /app/images/rainbow_colormap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/rainbow_colormap.png -------------------------------------------------------------------------------- /app/images/skybox/nx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/skybox/nx.jpg -------------------------------------------------------------------------------- /app/images/skybox/ny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/skybox/ny.jpg -------------------------------------------------------------------------------- /app/images/skybox/nz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/skybox/nz.jpg -------------------------------------------------------------------------------- /app/images/skybox/px.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/skybox/px.jpg -------------------------------------------------------------------------------- /app/images/skybox/py.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/skybox/py.jpg -------------------------------------------------------------------------------- /app/images/skybox/pz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NLeSC/ahn-pointcloud-viewer/2b135b5b831a135b343b191953349e29eb66c70c/app/images/skybox/pz.jpg -------------------------------------------------------------------------------- /app/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /app/scripts/app.js: -------------------------------------------------------------------------------- 1 | // The app 2 | /* global THREE:false, Potree:false */ 3 | 4 | (function() { 5 | 'use strict'; 6 | 7 | angular.module('pattyApp.three', []) 8 | .constant('THREE', THREE); 9 | 10 | angular.module('pattyApp.potree', []) 11 | .constant('Potree', Potree) 12 | /* 13 | .run(function(Potree, THREE) { 14 | Potree.TextSprite.prototype.setTextOriginal = Potree.TextSprite.prototype.setText; 15 | // var originalPotreeTextSpritePrototype = Potree.TextSprite.prototype; 16 | // originalPotreeTextSprite.prototype = originalPotreeTextSpritePrototype; 17 | Potree.TextSprite.prototype.setText = function(text) { 18 | console.log("jeuj"); 19 | Potree.TextSprite.prototype.setTextOriginal(text); 20 | }; 21 | console.log(Potree.TextSprite.prototype.setText === Potree.TextSprite.prototype.setTextOriginal); 22 | // Potree.TextSprite.prototype = originalPotreeTextSpritePrototype; 23 | */ 24 | 25 | // WORKING ON ISSUE #50 26 | /* var textSprite = Potree.TextSprite; 27 | var textSpritePrototype = Potree.TextSprite.prototype; 28 | var setText = Potree.TextSprite.prototype.setText; 29 | var setTextColor = Potree.TextSprite.prototype.setTextColor; 30 | var setBorderColor = Potree.TextSprite.prototype.setBorderColor; 31 | var setBackgroundColor = Potree.TextSprite.prototype.setBackgroundColor; 32 | var update = Potree.TextSprite.prototype.update; 33 | var roundRect = Potree.TextSprite.prototype.roundRect; 34 | Potree.TextSprite = function(text) { 35 | console.log('jeuj'); 36 | textSprite(text); 37 | }; 38 | Potree.TextSprite.prototype = new THREE.Object3D(); 39 | Potree.TextSprite.prototype.setText = setText; 40 | Potree.TextSprite.prototype.setTextColor = setTextColor; 41 | Potree.TextSprite.prototype.setBorderColor = setBorderColor; 42 | Potree.TextSprite.prototype.setBackgroundColor = setBackgroundColor; 43 | Potree.TextSprite.prototype.update = update; 44 | Potree.TextSprite.prototype.roundRect = roundRect; 45 | }) 46 | */ 47 | ; 48 | 49 | /** 50 | * @ngdoc overview 51 | * @name pattyApp 52 | * @description 53 | * # pattyApp 54 | * 55 | * Main module of the application. 56 | */ 57 | angular 58 | .module('pattyApp', [ 59 | 'ngAnimate', 60 | 'ngSanitize', 61 | 'ngTouch', 62 | 'ui.bootstrap', 63 | 'pattyApp.logos', 64 | 'pattyApp.searchbox', 65 | 'pattyApp.minimap', 66 | //'pattyApp.maximap', 67 | 'pattyApp.measuring', 68 | 'pattyApp.settings', 69 | 'pattyApp.helpModal', 70 | 'pattyApp.help', 71 | 'pattyApp.cameramodes', 72 | 'pattyApp.pointcloud', 73 | 'pattyApp.extract', 74 | 'pattyApp.biglegend', 75 | 'pattyApp.earthcontrols', 76 | 'pattyApp.gradients' 77 | ]) 78 | .config(function($compileProvider) { 79 | // data urls are not allowed by default, so whitelist them 80 | $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|blob):/); 81 | }) 82 | .run(function(DrivemapService) { 83 | DrivemapService.load(); 84 | }); 85 | 86 | angular.module('pattyApp.templates', []); 87 | angular.module('pattyApp.logos', []); 88 | angular.module('pattyApp.extract', ['pattyApp.core', 'angular-loading-bar', 'rt.debounce']); 89 | angular.module('pattyApp.utils', ['pattyApp.templates', 'toastr']); 90 | angular.module('pattyApp.core', ['pattyApp.utils']); 91 | angular.module('pattyApp.minimap', ['pattyApp.core', 'pattyApp.three']); 92 | //angular.module('pattyApp.maximap', ['pattyApp.core', 'pattyApp.three']); 93 | angular.module('pattyApp.measuring', ['pattyApp.potree', 'pattyApp.three', 'pattyApp.utils']); 94 | angular.module('pattyApp.gradients', []); 95 | angular.module('pattyApp.pointcloud', ['pattyApp.core', 'pattyApp.potree', 'pattyApp.three', 'pattyApp.measuring', 'cfp.loadingBar', 'pattyApp.extract', 'pattyApp.earthcontrols', 'pattyApp.utils', 'pattyApp.gradients']); 96 | angular.module('pattyApp.settings', ['pattyApp.pointcloud', 'ngFileUpload']); 97 | angular.module('pattyApp.help', ['pattyApp.templates']); 98 | angular.module('pattyApp.helpModal', []); 99 | angular.module('pattyApp.cameramodes', ['pattyApp.pointcloud']); 100 | angular.module('pattyApp.searchbox', ['pattyApp.core', 'pattyApp.pointcloud']); 101 | angular.module('pattyApp.biglegend', ['pattyApp.utils']); 102 | angular.module('pattyApp.earthcontrols', ['pattyApp.utils', 'pattyApp.three', 'pattyApp.pointcloud']); 103 | })(); 104 | -------------------------------------------------------------------------------- /app/scripts/biglegend/biglegend.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function BigLegendController($scope, DecimalAdjust, Messagebus, UserAgent, PointcloudService) { 5 | this.PointcloudService = PointcloudService; 6 | 7 | this.mobile = UserAgent.mobile; 8 | 9 | this.logarithmic = false; 10 | Messagebus.subscribe('logarithmicChange', function(event, value) { 11 | this.logarithmic = value; 12 | this.setLegendText(); 13 | }.bind(this)); 14 | 15 | this.legendText = [40, 30, 20, 10]; 16 | 17 | //Define the legend max initial value 18 | this.legendMin = PointcloudService.settings.heightMin; 19 | 20 | // Set watcher for change on the legend min setting, use it to publish changes. 21 | $scope.$watch('blc.legendMin', function(newValue, oldValue) { 22 | if (newValue === oldValue) { 23 | //Initialization, so we ignore this event. 24 | } else { 25 | this.setLegendText(); 26 | PointcloudService.settings.heightMin = newValue; 27 | } 28 | }.bind(this)); 29 | 30 | //Define the legend max initial value 31 | this.legendMax = PointcloudService.settings.heightMax; 32 | 33 | // Set watcher for change on the legend max setting, use it to publish changes. 34 | $scope.$watch('blc.legendMax', function(newValue, oldValue) { 35 | if (newValue === oldValue) { 36 | //Initialization, so we ignore this event. 37 | } else { 38 | this.setLegendText(); 39 | PointcloudService.settings.heightMax = newValue; 40 | } 41 | }.bind(this)); 42 | 43 | Messagebus.subscribe('ncwmsPaletteSelected', function(event, value) { 44 | this.setOnload(value.graphic); 45 | }.bind(this)); 46 | 47 | 48 | this.selectedUnits = 'm a.s.l.'; 49 | Messagebus.subscribe('ncwmsUnitsChange', function(event, value) { 50 | this.selectedUnits = value; 51 | }.bind(this)); 52 | 53 | this.setLegendText = function() { 54 | var diff = this.legendMax - this.legendMin; 55 | var interval = 0.2 * diff; 56 | 57 | if (!this.logarithmic) { 58 | this.legendText[3] = Math.round10((this.legendMin + interval), -2); 59 | this.legendText[2] = Math.round10((this.legendMin + 2 * interval), -2); 60 | this.legendText[1] = Math.round10((this.legendMin + 3 * interval), -2); 61 | this.legendText[0] = Math.round10((this.legendMin + 4 * interval), -2); 62 | } else { 63 | var logmin = Math.log10(this.legendMin); 64 | var logmax = Math.log10(this.legendMax); 65 | 66 | this.legendText[3] = Math.round10((Math.pow(10, 0.8 * logmin + 0.2 * logmax)), -2); 67 | this.legendText[2] = Math.round10((Math.pow(10, 0.6 * logmin + 0.4 * logmax)), -2); 68 | this.legendText[1] = Math.round10((Math.pow(10, 0.4 * logmin + 0.6 * logmax)), -2); 69 | this.legendText[0] = Math.round10((Math.pow(10, 0.2 * logmin + 0.8 * logmax)), -2); 70 | } 71 | }.bind(this); 72 | 73 | this.setOnload = function(imgURL) { 74 | var context = document.getElementById('bigLegendCanvas').getContext('2d'); 75 | var img = new Image(); 76 | img.src = imgURL; 77 | 78 | img.onload = function() { 79 | context.canvas.width = 5; 80 | context.canvas.height = 255; 81 | 82 | context.drawImage(img, 0, 0); 83 | }; 84 | }; 85 | 86 | /** 87 | * Generates a look-up texture for gradient values (height, intensity, ...) 88 | * 89 | */ 90 | this.generateLegendTexture = function(gradient, width, height) { 91 | // create canvas 92 | var canvas = document.createElement( 'canvas' ); 93 | canvas.width = width; 94 | canvas.height = height; 95 | 96 | // get context 97 | var context = canvas.getContext( '2d' ); 98 | 99 | // draw gradient 100 | context.rect( 0, 0, width, height ); 101 | var ctxGradient = context.createLinearGradient( 0, height, width, 0 ); 102 | 103 | for(var i = 0;i < gradient.length; i++){ 104 | var step = gradient[i]; 105 | 106 | ctxGradient.addColorStop(step[0], '#' + step[1].getHexString()); 107 | } 108 | 109 | context.fillStyle = ctxGradient; 110 | context.fill(); 111 | 112 | return context; 113 | }; 114 | 115 | this.setTexture = function(gradient) { 116 | var context = document.getElementById('bigLegendCanvas').getContext('2d'); 117 | var img = new Image(); 118 | var imageDataContext = this.generateLegendTexture(gradient, 1, 255); 119 | 120 | img.src = imageDataContext.canvas.toDataURL(); 121 | 122 | img.onload = function() { 123 | context.canvas.width = 1; 124 | context.canvas.height = 255; 125 | 126 | context.drawImage(img, 0, 0); 127 | }; 128 | }; 129 | 130 | Messagebus.subscribe('legendTexture change', function(event, value) { 131 | this.setTexture(value); 132 | }.bind(this)); 133 | 134 | //this.setOnload('images/rainbow_colormap.png'); 135 | } 136 | 137 | angular.module('pattyApp.biglegend').controller('BigLegendController', BigLegendController); 138 | })(); 139 | -------------------------------------------------------------------------------- /app/scripts/biglegend/biglegend.directive.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 |
7 | 8 |
9 |
10 |
11 | {{text}} 12 |
13 | 14 | 15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 |
{{blc.legendMax}}
23 |
24 | {{text}} 25 |
26 |
27 |
{{blc.legendMin}}
28 |
29 | 30 |
31 | 32 | 33 |
34 | 35 |
36 | 37 | {{blc.selectedUnits}} 38 |
39 |
40 | -------------------------------------------------------------------------------- /app/scripts/biglegend/biglegend.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function bigLegendDirective() { 5 | return { 6 | restrict: 'E', 7 | templateUrl: 'scripts/biglegend/biglegend.directive.html', 8 | controller: 'BigLegendController', 9 | controllerAs: 'blc' 10 | }; 11 | } 12 | 13 | angular.module('pattyApp.biglegend').directive('bigLegendDirective', bigLegendDirective); 14 | })(); 15 | -------------------------------------------------------------------------------- /app/scripts/core/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Constants of core module 3 | * 4 | * @namespace core 5 | */ 6 | /* global proj4:false */ 7 | /* global ol:false */ 8 | (function() { 9 | 'use strict'; 10 | 11 | angular.module('pattyApp.core') 12 | .constant('proj4', proj4) 13 | .constant('ol', ol) 14 | /** 15 | * @class core.pattyConf 16 | * @memberOf core 17 | */ 18 | .constant('pattyConf', { 19 | // to work without server uncomment below 20 | // SITES_JSON_URL: 'data/sites.json', 21 | /** 22 | * Url for json file with drivemap url, cameraPath, coordinate system, etc. 23 | * 24 | * @type {String} 25 | * @memberof core.pattyConf 26 | */ 27 | DRIVEMAP_JSON_URL: 'data/drivemap.json', 28 | /** 29 | * AHN web service endpoint url 30 | * @type {String} 31 | * @memberof core.pattyConf 32 | */ 33 | AHN_API_ENDPOINT: 'http://ahn2.pointclouds.nl/api', 34 | }); 35 | })(); 36 | -------------------------------------------------------------------------------- /app/scripts/core/drivemap.service.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace core 3 | */ 4 | (function() { 5 | 'use strict'; 6 | 7 | /** 8 | * @class 9 | * @memberOf core 10 | */ 11 | function DrivemapService($http, $q, $log, proj4, pattyConf) { 12 | var me = this; 13 | this.data = {}; 14 | var deferred = $q.defer(); 15 | 16 | /** 17 | * Promise for loading the sites remotely. 18 | * Can be used to perform action when loading sites has been completed. 19 | * 20 | * @type {Promise} 21 | */ 22 | this.ready = deferred.promise; 23 | 24 | /** 25 | * Load drivemap data from server 26 | * 27 | * @returns {Promise} 28 | */ 29 | this.load = function() { 30 | return $http.get(pattyConf.DRIVEMAP_JSON_URL).success(this.onLoad).error(this.onLoadFailure); 31 | }; 32 | 33 | this.onLoad = function(response) { 34 | me.data = response; 35 | 36 | me.registerProj4(); 37 | 38 | deferred.resolve(response); 39 | }; 40 | 41 | this.onLoadFailure = function() { 42 | $log.log('Failed to load drive map!!'); 43 | deferred.reject.apply(this, arguments); 44 | }; 45 | 46 | /** 47 | * The drivemap is in a coordinate system. 48 | * The coordinate system label is the crs. 49 | * The proj4 definition is the proj4 property of the first feature. 50 | */ 51 | this.registerProj4 = function() { 52 | proj4.defs(this.getCrs(), this.data.features[0].properties.proj4); 53 | }; 54 | 55 | this.getPointcloudUrl = function() { 56 | return this.data.features[0].properties.pointcloud; 57 | }; 58 | this.getCameraPath = function() { 59 | return this.data.features[0].geometry.coordinates; 60 | }; 61 | this.getLookPath = function() { 62 | return this.data.features[0].properties.lookatpath; 63 | }; 64 | this.getCrs = function() { 65 | return this.data.crs.properties.name; 66 | }; 67 | } 68 | 69 | angular.module('pattyApp.core') 70 | .service('DrivemapService', DrivemapService); 71 | })(); 72 | -------------------------------------------------------------------------------- /app/scripts/earthcontrols/earthcontrols.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function EarthcontrolsController(Messagebus) { 5 | this.enabled = true; 6 | 7 | this.toggleEarthcontrols = function() { 8 | this.enabled = !this.enabled; 9 | Messagebus.publish('earthcontrols enabled', this.enabled); 10 | }; 11 | } 12 | 13 | angular.module('pattyApp.earthcontrols') 14 | .controller('EarthcontrolsController', EarthcontrolsController); 15 | })(); 16 | -------------------------------------------------------------------------------- /app/scripts/earthcontrols/earthcontrols.directive.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/scripts/earthcontrols/earthcontrols.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function earthcontrolsDirective() { 5 | return { 6 | restrict: 'E', 7 | templateUrl: 'scripts/earthcontrols/earthcontrols.directive.html', 8 | controller: 'EarthcontrolsController', 9 | controllerAs: 'earthcontrols' 10 | }; 11 | } 12 | 13 | angular.module('pattyApp.earthcontrols') 14 | .directive('earthcontrolsDirective', earthcontrolsDirective); 15 | })(); 16 | -------------------------------------------------------------------------------- /app/scripts/earthcontrols/earthcontrols.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function EarthcontrolsService($rootScope, $location, Messagebus, THREE, PathControls, RailService) { // jshint ignore:line 5 | this.enabled = true; 6 | 7 | this.earthControls = null; 8 | this.pathcontrols = PathControls; 9 | 10 | this.elementRenderArea = null; 11 | 12 | var clock = new THREE.Clock(); 13 | 14 | this.init = function(camera, renderer, scenePointCloud, pointcloud, elementRenderArea) { 15 | this.earthControls = new THREE.EarthControls(camera, renderer, scenePointCloud); 16 | 17 | this.earthControls.addEventListener('proposeTransform', function() { 18 | // var demHeight = pointcloud.getDEMHeight(event.newPosition); 19 | // if(event.newPosition.y < demHeight){ 20 | // event.objections++; 21 | // } 22 | }); 23 | 24 | this.earthControls.pointclouds.push(pointcloud); 25 | 26 | if (this.enabled) { 27 | this.pathcontrols.disable(); 28 | } else { 29 | this.pathcontrols.enable(); 30 | } 31 | 32 | this.elementRenderArea = elementRenderArea; 33 | this.elementRenderArea.addEventListener('mousedown', this.mousedown.bind(this), false); 34 | }; 35 | 36 | this.update = function() { 37 | if(this.enabled) { 38 | this.earthControls.update(clock.getDelta()); 39 | } 40 | 41 | /* jshint ignore:start */ 42 | var waypoint = RailService.getCameraAndLookatLocation(); 43 | 44 | //store camera values in the URL 45 | $location.search({ 46 | camera_x:waypoint.cameraPosition[0], 47 | camera_y:waypoint.cameraPosition[1], 48 | camera_z:waypoint.cameraPosition[2], 49 | lookat_x:waypoint.lookatPosition[0], 50 | lookat_y:waypoint.lookatPosition[1], 51 | lookat_z:waypoint.lookatPosition[2] 52 | }).replace(); 53 | /* jshint ignore:end */ 54 | 55 | $rootScope.$applyAsync(); 56 | }; 57 | 58 | this.mousedown = function() { 59 | // claim focus when right click on canvas and not yet focused 60 | if (document.activeElement !== this.elementRenderArea) { 61 | this.elementRenderArea.focus(); 62 | } 63 | }; 64 | 65 | Messagebus.subscribe('earthcontrols suspended', function(event, value) { 66 | this.earthControls.enabled = !value; 67 | }.bind(this)); 68 | 69 | Messagebus.subscribe('earthcontrols enabled', function(event, value) { 70 | this.enabled = value; 71 | 72 | if (value) { 73 | this.pathcontrols.disable(); 74 | } else { 75 | this.pathcontrols.enable(); 76 | } 77 | 78 | this.earthControls.enabled = value; 79 | }.bind(this)); 80 | } 81 | 82 | angular.module('pattyApp.earthcontrols').service('EarthcontrolsService', EarthcontrolsService); 83 | })(); 84 | -------------------------------------------------------------------------------- /app/scripts/extract/extraction.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function ExtractionController(ExtractionSelectionService, pattyConf, Messagebus, $http, toastr) { 5 | this.selection = ExtractionSelectionService; 6 | this.email = ''; 7 | this.size = { 8 | coverage: 1, 9 | returnedPoints: 0, 10 | rawPoints: 0, 11 | level: 14 12 | }; 13 | this.selection.active = false; 14 | 15 | this.togglePanel = function() { 16 | if (!this.selection.active) { 17 | Messagebus.publish('closeOtherPanels', 'extraction'); 18 | 19 | this.selection.active = true; 20 | } else { 21 | this.selection.active = false; 22 | } 23 | }; 24 | 25 | this.panelClose = function(event, panelNameToRemainOpen) { 26 | if (panelNameToRemainOpen !== 'extraction') { 27 | this.selection.active = false; 28 | } 29 | }.bind(this); 30 | 31 | Messagebus.subscribe('closeOtherPanels', this.panelClose); 32 | 33 | /** 34 | * Update size data by requesting it from server. 35 | */ 36 | this.count = function() { 37 | var request = this.selection.toRequest(); 38 | var apiEndpoint = pattyConf.AHN_API_ENDPOINT; 39 | var url = apiEndpoint + '/size'; 40 | $http.post(url, request).success(function(data) { 41 | this.size = data; 42 | }.bind(this)).error(function() { 43 | console.log(arguments); 44 | }); 45 | }; 46 | 47 | /** 48 | * 49 | */ 50 | this.submit = function() { 51 | var request = this.selection.toRequest(); 52 | request.email = this.email; 53 | var apiEndpoint = pattyConf.AHN_API_ENDPOINT; 54 | var url = apiEndpoint + '/laz'; 55 | $http.post(url, request).success(function(data) { 56 | this.size = data; 57 | toastr.success('Will send e-mail to "' + request.email + '" when completed', 'Point extraction job submitted'); 58 | }.bind(this)).error(function() { 59 | console.log(arguments); 60 | toastr.error('Submit failed', 'for some reason'); 61 | }); 62 | this.showForm = false; 63 | }; 64 | } 65 | 66 | angular.module('pattyApp.extract') 67 | .controller('ExtractionController', ExtractionController); 68 | })(); 69 | -------------------------------------------------------------------------------- /app/scripts/extract/extraction.directive.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
Export points 4 | 7 |
8 |
9 |
10 | There are 3 ways to select a rectangle of points to extract. 11 |
    12 |
  • Click on the minimap to select points in the red rectangle.
  • 13 |
  • Click and drag out a rectangle on the 3D view.
  • 14 |
  • Set the extent numbers manually below.
  • 15 |
16 |
17 |
59 | 60 |
61 | 62 | -------------------------------------------------------------------------------- /app/scripts/extract/extraction.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function extractionPanel() { 5 | return { 6 | restrict: 'E', 7 | templateUrl: 'scripts/extract/extraction.directive.html', 8 | controller: 'ExtractionController', 9 | controllerAs: 'ec' 10 | }; 11 | } 12 | 13 | angular.module('pattyApp.extract') 14 | .directive('extractionPanel', extractionPanel); 15 | })(); 16 | -------------------------------------------------------------------------------- /app/scripts/extract/extraction.selection.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function ExtractionSelectionService(Messagebus, debounce) { 5 | this._active = false; 6 | 7 | this._left = 93720.22; 8 | this._bottom = 436899.97; 9 | this._right = 94428.37; 10 | this._top = 438334.32; 11 | 12 | this.debouncedSendUpdate = function() { 13 | this.checkSwapCoordinates(); 14 | Messagebus.publish('extractionSelectionChanged', this.toRequest()); 15 | }.bind(this); 16 | 17 | this.sendUpdate = debounce(500, this.debouncedSendUpdate); 18 | 19 | this.updateValue = function(name, newValue) { 20 | if (newValue !== this[name]) { 21 | this[name] = newValue; 22 | this.sendUpdate(); 23 | } 24 | }; 25 | 26 | Object.defineProperty(this, 'active', { 27 | get: function() { return this._active; }, 28 | set: function(newValue) { 29 | if (newValue !== this._active) { 30 | Messagebus.publish('extractionSelectionActivationChanged', newValue); 31 | } 32 | this._active = newValue; 33 | } 34 | }); 35 | 36 | Object.defineProperty(this, 'left', { 37 | get: function() { return this._left; }, 38 | set: function(newValue) { 39 | this.updateValue('_left', newValue); 40 | } 41 | }); 42 | 43 | Object.defineProperty(this, 'top', { 44 | get: function() { return this._top; }, 45 | set: function(newValue) { 46 | this.updateValue('_top', newValue); 47 | } 48 | }); 49 | 50 | Object.defineProperty(this, 'right', { 51 | get: function() { return this._right; }, 52 | set: function(newValue) { 53 | this.updateValue('_right', newValue); 54 | } 55 | }); 56 | 57 | Object.defineProperty(this, 'bottom', { 58 | get: function() { return this._bottom; }, 59 | set: function(newValue) { 60 | this.updateValue('_bottom', newValue); 61 | } 62 | }); 63 | 64 | this.checkSwapCoordinates = function() { 65 | var temp = -1; 66 | if (this._bottom > this._top) { 67 | temp = this._top; 68 | this._top = this._bottom; 69 | this._bottom = temp; 70 | } 71 | if (this._left > this._right) { 72 | temp = this._right; 73 | this._right = this._left; 74 | this._left = temp; 75 | } 76 | }; 77 | 78 | this.setBottomLeftCoordinates = function(coords) { 79 | this.bottom = coords.lat; 80 | this.left = coords.lon; 81 | }; 82 | 83 | this.setTopRightCoordinates = function(coords) { 84 | this.top = coords.lat; 85 | this.right = coords.lon; 86 | }; 87 | 88 | this.toRequest = function() { 89 | var request = { 90 | left: this._left, 91 | bottom: this._bottom, 92 | right: this._right, 93 | top: this._top 94 | }; 95 | return request; 96 | }; 97 | } 98 | 99 | angular.module('pattyApp.extract').service('ExtractionSelectionService', ExtractionSelectionService); 100 | })(); 101 | -------------------------------------------------------------------------------- /app/scripts/extract/minimap.extraction.selection.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function MinimapExtractionSelectionService(ExtractionSelectionService, ol, Messagebus) { 5 | this.source = new ol.source.Vector({ 6 | wrapX: false 7 | }); 8 | 9 | this.layer = new ol.layer.Vector({ 10 | source: this.source, 11 | style: new ol.style.Style({ 12 | fill: new ol.style.Fill({ 13 | color: 'rgba(255, 255, 255, 0.2)' 14 | }), 15 | stroke: new ol.style.Stroke({ 16 | color: '#f00', 17 | width: 2 18 | }) 19 | }), 20 | visible: false 21 | }); 22 | this.drawing = false; 23 | 24 | this.geometryFunction = function(coordinates, geometry) { 25 | if (!geometry) { 26 | geometry = new ol.geom.Polygon(null); 27 | } 28 | var start = coordinates[0]; 29 | var end = coordinates[1]; 30 | geometry.setCoordinates([ 31 | [start, [start[0], end[1]], end, [end[0], start[1]], start] 32 | ]); 33 | return geometry; 34 | }; 35 | 36 | this.drawer = new ol.interaction.Draw({ 37 | source: this.source, 38 | type: 'LineString', 39 | geometryFunction: this.geometryFunction, 40 | maxPoints: 2, 41 | style: new ol.style.Style({ 42 | fill: new ol.style.Fill({ 43 | color: 'rgba(255, 255, 255, 0.2)' 44 | }), 45 | stroke: new ol.style.Stroke({ 46 | color: '#f00', 47 | width: 3 48 | }), 49 | // cross as mouse pointer 50 | image: new ol.style.RegularShape({ 51 | stroke: new ol.style.Stroke({ 52 | color: '#f00', 53 | width: 2 54 | }), 55 | points: 4, 56 | radius: 10, 57 | radius2: 0, 58 | angle: 0 59 | }) 60 | }) 61 | }); 62 | 63 | this.onDrawStart = function() { 64 | // only one selection can be drawn at one time 65 | this.source.clear(); 66 | this.drawing = true; 67 | }; 68 | 69 | this.onDrawEnd = function(interaction) { 70 | var coordinates = interaction.feature.getGeometry().getCoordinates(); 71 | 72 | function round2Dec(value) { 73 | return Math.round(value * 100) / 100; 74 | } 75 | 76 | var topright = { 77 | lon: round2Dec(coordinates[0][3][0]), 78 | lat: round2Dec(coordinates[0][3][1]) 79 | }; 80 | var bottomleft = { 81 | lon: round2Dec(coordinates[0][1][0]), 82 | lat: round2Dec(coordinates[0][1][1]) 83 | }; 84 | ExtractionSelectionService.setTopRightCoordinates(topright); 85 | ExtractionSelectionService.setBottomLeftCoordinates(bottomleft); 86 | this.drawing = false; 87 | }; 88 | 89 | this.remoteSelectionChanged = function(event, bbox) { 90 | if (this.drawing) { 91 | // dont listen to changes we made ourselves 92 | return; 93 | } 94 | this.drawSelection(bbox); 95 | }; 96 | 97 | this.drawSelection = function(bbox) { 98 | // resize dragbox 99 | var coordinates = [ 100 | [ 101 | [ 102 | bbox.left, bbox.top 103 | ], 104 | [ 105 | bbox.left, bbox.bottom 106 | ], 107 | [ 108 | bbox.right, bbox.bottom 109 | ], 110 | [ 111 | bbox.right, bbox.top 112 | ], 113 | [ 114 | bbox.left, bbox.top 115 | ] 116 | ] 117 | ]; 118 | var feature = this.source.getFeatures()[0]; 119 | if (feature) { 120 | var geom = feature.getGeometry(); 121 | geom.setCoordinates(coordinates); 122 | } else { 123 | // no selection has been made in minimap before 124 | feature = new ol.Feature({ 125 | geometry: new ol.geom.Polygon(coordinates) 126 | }); 127 | this.source.addFeature(feature); 128 | } 129 | }; 130 | 131 | this.activationChanged = function(event, active) { 132 | this.layer.setVisible(active); 133 | this.drawer.setActive(active); 134 | if (active) { 135 | // draw existing selection 136 | this.drawSelection(ExtractionSelectionService); 137 | } 138 | }; 139 | 140 | this.init = function(map) { 141 | map.addLayer(this.layer); 142 | map.addInteraction(this.drawer); 143 | }; 144 | 145 | this.drawer.setActive(false); 146 | this.drawer.on('drawstart', this.onDrawStart.bind(this)); 147 | this.drawer.on('drawend', this.onDrawEnd.bind(this)); 148 | Messagebus.subscribe('extractionSelectionChanged', this.remoteSelectionChanged.bind(this)); 149 | Messagebus.subscribe('extractionSelectionActivationChanged', this.activationChanged.bind(this)); 150 | } 151 | 152 | angular.module('pattyApp.extract') 153 | .service('MinimapExtractionSelectionService', MinimapExtractionSelectionService); 154 | })(); 155 | -------------------------------------------------------------------------------- /app/scripts/extract/pointcloud.extraction.drawing.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function ExtractionDrawingService(THREE, SceneService, Messagebus) { 5 | this.color = new THREE.Color(0xffffff); 6 | 7 | this.renderer = null; 8 | this.scene = null; 9 | this.camera = null; 10 | this.selectionMesh = null; 11 | this.intermediateMesh = null; 12 | 13 | this.init = function(renderer, scene, camera) { 14 | this.renderer = renderer; 15 | this.scene = scene; 16 | this.camera = camera; 17 | }; 18 | 19 | this.remoteSelectionChanged = function(event, bbox) { 20 | this.scene.remove(this.selectionMesh); 21 | 22 | var leftTopLocal = SceneService.toLocal(new THREE.Vector3(bbox.left, bbox.top, 0)); 23 | var rightTopLocal = SceneService.toLocal(new THREE.Vector3(bbox.right, bbox.top, 0)); 24 | var rightBottomLocal = SceneService.toLocal(new THREE.Vector3(bbox.right, bbox.bottom, 0)); 25 | var leftBottomLocal = SceneService.toLocal(new THREE.Vector3(bbox.left, bbox.bottom, 0)); 26 | 27 | this.selectionMesh = this.buildSelectionGeometry(leftTopLocal, rightTopLocal, rightBottomLocal, leftBottomLocal, 0xFF0000); 28 | this.scene.add(this.selectionMesh); 29 | }; 30 | 31 | Messagebus.subscribe('extractionSelectionChanged', this.remoteSelectionChanged.bind(this)); 32 | 33 | this.setIntermediate = function(mouseDownPoint, mouseMovePoint) { 34 | this.scene.remove(this.selectionMesh); 35 | this.scene.remove(this.intermediateMesh); 36 | 37 | var leftTopLocal = new THREE.Vector3(mouseDownPoint.x, 0, mouseDownPoint.z); 38 | var rightTopLocal = new THREE.Vector3(mouseMovePoint.x, 0, mouseDownPoint.z); 39 | var rightBottomLocal = new THREE.Vector3(mouseMovePoint.x, 0, mouseMovePoint.z); 40 | var leftBottomLocal = new THREE.Vector3(mouseDownPoint.x, 0, mouseMovePoint.z); 41 | 42 | this.intermediateMesh = this.buildSelectionGeometry(leftTopLocal, rightTopLocal, rightBottomLocal, leftBottomLocal, 0xFF0000); 43 | this.scene.add(this.intermediateMesh); 44 | }; 45 | 46 | this.removeIntermediate = function() { 47 | this.scene.remove(this.intermediateMesh); 48 | }; 49 | 50 | this.buildSelectionGeometry = function(leftTopLocal, rightTopLocal, rightBottomLocal, leftBottomLocal, color) { 51 | var boxMaterial = new THREE.MeshBasicMaterial({ 52 | color: color, 53 | side: THREE.DoubleSide, 54 | transparent: true, 55 | wireframe: false, 56 | opacity: 1 57 | // overdraw: 0.5 58 | }); 59 | 60 | var geometry = new THREE.Geometry(); 61 | var translationMatrix = null; 62 | 63 | var topBox = new THREE.BoxGeometry(rightTopLocal.x-leftTopLocal.x+50, 25, 25); 64 | translationMatrix = new THREE.Matrix4().setPosition(new THREE.Vector3(leftTopLocal.x+ 0.5*(rightTopLocal.x-leftTopLocal.x), 45, leftTopLocal.z+12)); 65 | topBox.applyMatrix(translationMatrix); 66 | 67 | var rightBox = new THREE.BoxGeometry(25, 25, rightTopLocal.z-rightBottomLocal.z+50); 68 | translationMatrix = new THREE.Matrix4().setPosition(new THREE.Vector3(rightBottomLocal.x+12, 45, rightBottomLocal.z+0.5*(rightTopLocal.z-rightBottomLocal.z))); 69 | rightBox.applyMatrix(translationMatrix); 70 | 71 | var bottomBox = new THREE.BoxGeometry(rightBottomLocal.x-leftBottomLocal.x+50, 25, 25); 72 | translationMatrix = new THREE.Matrix4().setPosition(new THREE.Vector3(leftBottomLocal.x+ 0.5*(rightBottomLocal.x-leftBottomLocal.x), 45, leftBottomLocal.z-12)); 73 | bottomBox.applyMatrix(translationMatrix); 74 | 75 | var leftBox = new THREE.BoxGeometry(25, 25, leftTopLocal.z-leftBottomLocal.z+50); 76 | translationMatrix = new THREE.Matrix4().setPosition(new THREE.Vector3(leftTopLocal.x-12, 45, leftBottomLocal.z+0.5*(leftTopLocal.z-leftBottomLocal.z))); 77 | leftBox.applyMatrix(translationMatrix); 78 | 79 | geometry.merge(topBox); 80 | geometry.merge(rightBox); 81 | geometry.merge(bottomBox); 82 | geometry.merge(leftBox); 83 | 84 | var mesh = new THREE.Mesh(geometry, boxMaterial); 85 | return mesh; 86 | }; 87 | 88 | this.activationChanged = function(event, active) { 89 | if (active) { 90 | if (this.selectionMesh !== null) { 91 | this.scene.add(this.selectionMesh); 92 | } 93 | if (this.intermediateMesh !== null) { 94 | this.scene.add(this.intermediateMesh); 95 | } 96 | this.show = true; 97 | } else { 98 | this.scene.remove(this.selectionMesh); 99 | this.scene.remove(this.intermediateMesh); 100 | this.show = false; 101 | } 102 | }; 103 | 104 | Messagebus.subscribe('extractionSelectionActivationChanged', this.activationChanged.bind(this)); 105 | 106 | } 107 | 108 | angular.module('pattyApp.extract').service('ExtractionDrawingService', ExtractionDrawingService); 109 | })(); 110 | -------------------------------------------------------------------------------- /app/scripts/extract/pointcloud.extraction.selection.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function PointcloudExtractionSelectionService(THREE, SceneService, ExtractionSelectionService, ExtractionDrawingService, Messagebus, Potree) { 5 | var me = this; 6 | 7 | this.selectionActive = false; 8 | this.mouseDownPoint = null; 9 | this.mouseDownLocalPoint = null; 10 | this.otherPoint = null; 11 | 12 | this.renderer = null; 13 | this.scene = null; 14 | this.camera = null; 15 | this.mesh = null; 16 | 17 | this.mouse = {x: 0, y: 0}; 18 | 19 | this.init = function(renderer, scene, camera) { 20 | this.renderer = renderer; 21 | this.scene = scene; 22 | this.camera = camera; 23 | 24 | me.renderer.domElement.addEventListener( 'mousemove', onMouseMove, false ); 25 | me.renderer.domElement.addEventListener( 'mousedown', onMouseDown, false ); 26 | me.renderer.domElement.addEventListener( 'mouseup', onMouseUp, true ); 27 | }; 28 | 29 | this.getMousePointCloudIntersection = function(){ 30 | var vector = new THREE.Vector3( me.mouse.x, me.mouse.y, 0.5 ); 31 | vector.unproject(me.camera); 32 | var direction = vector.sub(me.camera.position).normalize(); 33 | var ray = new THREE.Ray(me.camera.position, direction); 34 | 35 | var pointClouds = []; 36 | me.scene.traverse(function(object){ 37 | if(object instanceof Potree.PointCloudOctree){ 38 | pointClouds.push(object); 39 | } 40 | }); 41 | 42 | var closestPoint = null; 43 | var closestPointDistance = null; 44 | 45 | for(var i = 0; i < pointClouds.length; i++){ 46 | var pointcloud = pointClouds[i]; 47 | var point = pointcloud.pick(me.renderer, me.camera, ray, {accuracy: 0.5}); 48 | 49 | if(!point){ 50 | continue; 51 | } 52 | 53 | var distance = me.camera.position.distanceTo(point.position); 54 | 55 | if(!closestPoint || distance < closestPointDistance){ 56 | closestPoint = point; 57 | closestPointDistance = distance; 58 | } 59 | } 60 | 61 | return closestPoint ? closestPoint.position : null; 62 | }; 63 | 64 | var scope = this; 65 | 66 | function onMouseDown(event){ 67 | if(me.selectionActive) { 68 | if(event.which === 1) { 69 | me.mouseDownLocalPoint = scope.getMousePointCloudIntersection(); 70 | 71 | if(me.mouseDownLocalPoint){ 72 | me.mouseDownPoint = SceneService.toGeo(me.mouseDownLocalPoint); 73 | } 74 | } 75 | } 76 | } 77 | 78 | function onMouseUp(event) { 79 | if(me.selectionActive) { 80 | if(event.which === 1) { 81 | var I = scope.getMousePointCloudIntersection(); 82 | 83 | if(I){ 84 | me.otherPoint = SceneService.toGeo(I); 85 | 86 | var topRight = {lat:me.mouseDownPoint.y, lon:me.mouseDownPoint.x}; 87 | var bottomLeft = {lat:me.otherPoint.y, lon:me.otherPoint.x}; 88 | 89 | ExtractionSelectionService.setTopRightCoordinates(topRight); 90 | ExtractionSelectionService.setBottomLeftCoordinates(bottomLeft); 91 | 92 | me.mouseDownLocalPoint = null; 93 | } 94 | } 95 | } 96 | } 97 | 98 | function onMouseMove(event){ 99 | if(me.selectionActive) { 100 | me.mouse.x = ( event.clientX / me.renderer.domElement.clientWidth ) * 2 - 1; 101 | me.mouse.y = - ( event.clientY / me.renderer.domElement.clientHeight ) * 2 + 1; 102 | 103 | var mouseMoveLocalPoint = scope.getMousePointCloudIntersection(); 104 | 105 | if(me.mouseDownLocalPoint && mouseMoveLocalPoint){ 106 | ExtractionDrawingService.setIntermediate(me.mouseDownLocalPoint, mouseMoveLocalPoint); 107 | } else { 108 | ExtractionDrawingService.removeIntermediate(); 109 | } 110 | } 111 | } 112 | 113 | this.activationChanged = function(event, active) { 114 | this.selectionActive = active; 115 | Messagebus.publish('earthcontrols suspended', active); 116 | }; 117 | 118 | Messagebus.subscribe('extractionSelectionActivationChanged', this.activationChanged.bind(this)); 119 | 120 | } 121 | 122 | angular.module('pattyApp.extract').service('PointcloudExtractionSelectionService', PointcloudExtractionSelectionService); 123 | })(); 124 | -------------------------------------------------------------------------------- /app/scripts/help/help.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function HelpController() { 5 | } 6 | 7 | angular.module('pattyApp.help') 8 | .controller('HelpController', HelpController); 9 | })(); 10 | -------------------------------------------------------------------------------- /app/scripts/help/help.directive.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/scripts/help/help.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function pattyHelp() { 5 | return { 6 | restrict: 'E', 7 | templateUrl: 'scripts/help/help.directive.html', 8 | controller: 'HelpController', 9 | controllerAs: 'hc' 10 | }; 11 | } 12 | 13 | angular.module('pattyApp.help') 14 | .directive('pattyHelp', pattyHelp); 15 | })(); 16 | -------------------------------------------------------------------------------- /app/scripts/helpModal/helpModal.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function HelpModalController($window, UserAgent) { 5 | this.mobile = UserAgent.mobile; 6 | this.doNotShow = false; 7 | 8 | this.dontShowClicked = function() { 9 | if (this.doNotShow) { 10 | console.log('dont show clicked'); 11 | $window.localStorage.message = 'Do not show settings'; 12 | } else { 13 | console.log('show clicked'); 14 | $window.localStorage.message = ''; 15 | } 16 | }; 17 | 18 | this.checkBrowser = function() { 19 | var userAgent = $window.navigator.userAgent; 20 | 21 | var browsers = {chrome: /chrome/i, edge: /edge/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer/i}; 22 | 23 | for(var key in browsers) { 24 | if (browsers[key].test(userAgent)) { 25 | return key; 26 | } 27 | } 28 | 29 | return 'unknown'; 30 | }; 31 | 32 | this.init = function() { 33 | console.log('$window.localStorage.message : ' + $window.localStorage.message); 34 | if ($window.localStorage.message === 'Do not show settings') { 35 | this.doNotShow = true; 36 | } else { 37 | this.doNotShow = false; 38 | angular.element('#helpModal').modal( 39 | { 40 | 'show' : 'true' 41 | } 42 | ); 43 | } 44 | }; 45 | 46 | this.onClose = function() { 47 | }; 48 | 49 | if (!this.mobile) { 50 | this.chrome = (this.checkBrowser() === 'chrome' || this.checkBrowser() === 'edge'); 51 | } 52 | } 53 | 54 | angular.module('pattyApp.helpModal').controller('HelpModalController', HelpModalController); 55 | })(); 56 | -------------------------------------------------------------------------------- /app/scripts/helpModal/helpModal.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function helpModalDirective() { 5 | return { 6 | restrict: 'E', 7 | templateUrl: 'scripts/helpModal/helpModal.directive.html', 8 | link: function(scope) { 9 | scope.helpModal.init(); 10 | }, 11 | controller: 'HelpModalController', 12 | controllerAs: 'helpModal' 13 | }; 14 | } 15 | 16 | angular.module('pattyApp.helpModal').directive('helpModalDirective', helpModalDirective); 17 | })(); 18 | -------------------------------------------------------------------------------- /app/scripts/logos/logos.directive.html: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /app/scripts/logos/logos.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function logoBoxDirective() { 5 | return { 6 | restrict: 'E', 7 | templateUrl: 'scripts/logos/logos.directive.html' 8 | }; 9 | } 10 | 11 | angular.module('pattyApp.logos').directive('logoBoxDirective', logoBoxDirective); 12 | })(); 13 | -------------------------------------------------------------------------------- /app/scripts/measuring/measuring.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function MeasuringController(MeasuringService, Messagebus) { 5 | this.showToolboxTray = false; 6 | this.showTransformationToolboxTray = false; 7 | 8 | this.distanceActive = false; 9 | this.angleActive = false; 10 | this.areaActive = false; 11 | this.volumeActive = false; 12 | this.heightProfileActive = false; 13 | this.clipVolumeActive = false; 14 | 15 | this.measuringService = MeasuringService; 16 | 17 | this.toggleToolbox = function() { 18 | this.resetState(); 19 | 20 | if (!this.showToolboxTray) { 21 | Messagebus.publish('closeOtherPanels', 'toolbox'); 22 | 23 | this.showToolboxTray = true; 24 | } else { 25 | this.showToolboxTray = false; 26 | } 27 | }; 28 | 29 | this.panelClose = function(event, panelNameToRemainOpen) { 30 | if (panelNameToRemainOpen !== 'toolbox') { 31 | this.resetState(); 32 | this.showToolboxTray = false; 33 | } 34 | }.bind(this); 35 | 36 | Messagebus.subscribe('closeOtherPanels', this.panelClose); 37 | 38 | this.resetState = function() { 39 | this.distanceActive = false; 40 | this.angleActive = false; 41 | this.areaActive = false; 42 | this.volumeActive = false; 43 | this.heightProfileActive = false; 44 | this.clipVolumeActive = false; 45 | 46 | this.showTransformationToolboxTray = false; 47 | 48 | this.measuringService.clear(); 49 | }; 50 | 51 | this.isTransformationRotate = function() { 52 | var result = false; 53 | if (this.measuringService.activeTransformationTool === this.measuringService.transformationTools.ROTATE) { 54 | result = true; 55 | } 56 | return result; 57 | }; 58 | 59 | this.isTransformationTranslate = function() { 60 | var result = false; 61 | if (this.measuringService.activeTransformationTool === this.measuringService.transformationTools.TRANSLATE) { 62 | result = true; 63 | } 64 | return result; 65 | }; 66 | 67 | this.isTransformationScale = function() { 68 | var result = false; 69 | if (this.measuringService.activeTransformationTool === this.measuringService.transformationTools.SCALE) { 70 | result = true; 71 | } 72 | return result; 73 | }; 74 | 75 | this.startDistance = function() { 76 | this.resetState(); 77 | this.distanceActive = true; 78 | this.measuringService.startDistance(); 79 | }; 80 | 81 | this.startAngle = function() { 82 | this.resetState(); 83 | this.angleActive = true; 84 | this.measuringService.startAngle(); 85 | }; 86 | 87 | this.startArea = function() { 88 | this.resetState(); 89 | this.areaActive = true; 90 | this.measuringService.startArea(); 91 | }; 92 | 93 | this.startAngle = function() { 94 | this.resetState(); 95 | this.angleActive = true; 96 | this.measuringService.startAngle(); 97 | }; 98 | 99 | this.startVolume = function() { 100 | this.resetState(); 101 | this.volumeActive = true; 102 | this.showTransformationToolboxTray = true; 103 | this.measuringService.startVolume(); 104 | 105 | }; 106 | 107 | this.startHeightProfile = function() { 108 | this.resetState(); 109 | this.heightProfileActive = true; 110 | this.measuringService.startHeightProfile(); 111 | }; 112 | 113 | this.startClipVolume = function() { 114 | this.resetState(); 115 | this.clipVolumeActive = true; 116 | this.showTransformationToolboxTray = true; 117 | this.measuringService.startClipVolume(); 118 | }; 119 | 120 | this.toggleRotate = function() { 121 | this.measuringService.activeTransformationTool = this.measuringService.transformationTools.ROTATE; 122 | this.resetState(); 123 | this.showTransformationToolboxTray = true; 124 | this.measuringService.tools.transformation.rotate(); 125 | }; 126 | 127 | this.toggleTranslate = function() { 128 | this.measuringService.activeTransformationTool = this.measuringService.transformationTools.TRANSLATE; 129 | this.resetState(); 130 | this.showTransformationToolboxTray = true; 131 | this.measuringService.tools.transformation.translate(); 132 | }; 133 | 134 | this.toggleScale = function() { 135 | this.measuringService.activeTransformationTool = this.measuringService.transformationTools.SCALE; 136 | this.resetState(); 137 | this.showTransformationToolboxTray = true; 138 | this.measuringService.tools.transformation.scale(); 139 | }; 140 | } 141 | 142 | angular.module('pattyApp.measuring').controller('MeasuringController', MeasuringController); 143 | })(); 144 | -------------------------------------------------------------------------------- /app/scripts/measuring/measuring.directive.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 | 19 | 20 | 21 |
22 | -------------------------------------------------------------------------------- /app/scripts/measuring/measuring.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function measuringDirective() { 5 | return { 6 | restrict: 'E', 7 | templateUrl: 'scripts/measuring/measuring.directive.html', 8 | controller: 'MeasuringController', 9 | controllerAs: 'measuring' 10 | }; 11 | } 12 | 13 | angular.module('pattyApp.measuring').directive('measuringDirective', measuringDirective); 14 | })(); 15 | -------------------------------------------------------------------------------- /app/scripts/measuring/measuring.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function MeasuringService($rootScope, Potree, THREE, $window) { 5 | this.tools = { 6 | measuring: null, 7 | volume: null, 8 | heightprofile: null, 9 | clipvolume: null, 10 | transformation: null 11 | }; 12 | 13 | this.transformationTools = { 14 | TRANSLATE: 0, 15 | ROTATE: 1, 16 | SCALE: 2 17 | }; 18 | 19 | this.activeTransformationTool = this.transformationTools.ROTATE; 20 | 21 | this.pointcloud = null; 22 | this.sitePointcloud = null; 23 | 24 | this.profileWidth = 0.1; 25 | this.initialized = false; 26 | 27 | this.onKeyDown = function(event) { 28 | //console.log(event.keyCode); 29 | 30 | if (event.keyCode === 69) { 31 | // e pressed 32 | this.activeTransformationTool = this.transformationTools.SCALE; 33 | $rootScope.$digest(); 34 | 35 | this.tools.transformation.scale(); 36 | } else if (event.keyCode === 82) { 37 | // r pressed 38 | this.activeTransformationTool = this.transformationTools.ROTATE; 39 | $rootScope.$digest(); 40 | 41 | this.tools.transformation.rotate(); 42 | } else if (event.keyCode === 84) { 43 | // t pressed 44 | this.activeTransformationTool = this.transformationTools.TRANSLATE; 45 | $rootScope.$digest(); 46 | 47 | this.tools.transformation.translate(); 48 | } 49 | }; 50 | 51 | this.clear = function() { 52 | this.clearStandardPotreeMeasurementTool(this.tools.measuring); 53 | this.clearVolumes(); 54 | this.clearProfile(); 55 | }; 56 | 57 | this.clearStandardPotreeMeasurementTool = function(tool) { 58 | tool.measurements = []; 59 | tool.sceneMeasurement = new THREE.Scene(); 60 | tool.sceneRoot = new THREE.Object3D(); 61 | tool.sceneMeasurement.add(tool.sceneRoot); 62 | tool.light = new THREE.DirectionalLight( 0xffffff, 1 ); 63 | tool.light.position.set( 0, 0, 10 ); 64 | tool.light.lookAt(new THREE.Vector3(0,0,0)); 65 | tool.sceneMeasurement.add( tool.light ); 66 | }; 67 | 68 | this.clearVolumes = function() { 69 | this.tools.volume.volumes = []; 70 | this.tools.volume.sceneVolume = new THREE.Scene(); 71 | }; 72 | 73 | this.clearProfile = function() { 74 | this.tools.heightprofile.profiles = []; 75 | this.tools.heightprofile.sceneProfile = new THREE.Scene(); 76 | this.tools.heightprofile.sceneRoot = new THREE.Object3D(); 77 | this.tools.heightprofile.sceneProfile.add(this.tools.heightprofile.sceneRoot); 78 | }; 79 | 80 | this.init = function(renderer, scene, camera) { 81 | this.tools.measuring = new Potree.MeasuringTool(scene, camera, renderer); 82 | this.tools.volume = new Potree.VolumeTool(scene, camera, renderer); 83 | this.tools.heightprofile = new Potree.ProfileTool(scene, camera, renderer); 84 | this.tools.transformation = new Potree.TransformationTool(scene, camera, renderer); 85 | // TODO do pollute global namespace, but Potree.VolumeTool uses the global var 86 | $window.transformationTool = this.tools.transformation; 87 | 88 | $window.addEventListener('keydown', this.onKeyDown.bind(this), false); 89 | this.initialized = true; 90 | }; 91 | 92 | this.setPointcloud = function(pointcloud) { 93 | this.pointcloud = pointcloud; 94 | }; 95 | 96 | this.setSitePointcloud = function(pointcloud) { 97 | this.sitePointcloud = pointcloud; 98 | }; 99 | 100 | this.startDistance = function() { 101 | if (this.tools.measuring) { 102 | this.tools.measuring.startInsertion({showDistances: true, showArea: false, closed: false}); 103 | } 104 | }; 105 | 106 | this.startAngle = function() { 107 | if (this.tools.measuring) { 108 | this.tools.measuring.startInsertion({showDistances: false, showAngles: true, showArea: false, closed: true, maxMarkers: 3}); 109 | } 110 | }; 111 | 112 | this.startArea = function() { 113 | if (this.tools.measuring) { 114 | this.tools.measuring.startInsertion({showDistances: true, showArea: true, closed: true}); 115 | } 116 | }; 117 | 118 | this.startVolume = function() { 119 | if (this.tools.volume) { 120 | this.tools.volume.startInsertion(); 121 | } 122 | }; 123 | 124 | this.startHeighProfile = function() { 125 | if (this.tools.heightprofile) { 126 | this.tools.heightprofile.startInsertion({ 127 | width: this.profileWidth 128 | }); 129 | } 130 | }; 131 | 132 | this.startClipVolume = function() { 133 | if (this.tools.volume) { 134 | this.tools.volume.startInsertion({ 135 | clip: true 136 | }); 137 | } 138 | }; 139 | 140 | this.render = function() { 141 | if (this.initialized) { 142 | this.tools.heightprofile.render(); 143 | this.tools.volume.render(); 144 | 145 | this.tools.measuring.renderer.clearDepth(); 146 | this.tools.measuring.render(); 147 | this.tools.transformation.render(); 148 | } 149 | }; 150 | 151 | var emptyMatrix = new THREE.Matrix4(); 152 | 153 | this.update = function() { 154 | if (this.initialized) { 155 | this.tools.volume.update(); 156 | this.tools.transformation.update(); 157 | this.tools.heightprofile.update(); 158 | 159 | var clipBoxes = []; 160 | 161 | for (var i = 0; i < this.tools.heightprofile.profiles.length; i++) { 162 | var profile = this.tools.heightprofile.profiles[i]; 163 | 164 | for (var j = 0; j < profile.boxes.length; j++) { 165 | var box = profile.boxes[j]; 166 | box.updateMatrixWorld(); 167 | var boxInverse = emptyMatrix.identity().getInverse(box.matrixWorld); 168 | clipBoxes.push(boxInverse); 169 | } 170 | } 171 | 172 | for (var k = 0; k < this.tools.volume.volumes.length; k++) { 173 | var volume = this.tools.volume.volumes[k]; 174 | 175 | if (volume.clip) { 176 | volume.updateMatrixWorld(); 177 | var boxInverseV = emptyMatrix.identity().getInverse(volume.matrixWorld); 178 | 179 | clipBoxes.push(boxInverseV); 180 | } 181 | } 182 | 183 | if (this.pointcloud) { 184 | this.pointcloud.material.setClipBoxes(clipBoxes); 185 | } 186 | 187 | if (this.sitePointcloud) { 188 | this.sitePointcloud.material.setClipBoxes(clipBoxes); 189 | } 190 | } 191 | }; 192 | } 193 | 194 | angular.module('pattyApp.measuring').service('MeasuringService', MeasuringService); 195 | })(); 196 | -------------------------------------------------------------------------------- /app/scripts/minimap/cam-frustum.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function CamFrustumService(ol, THREE) { 5 | this.camFrustum = new ol.geom.LineString([[0, 0], [1, 0], [0, 1]]); 6 | var featureVector = new ol.source.Vector({ 7 | features: [new ol.Feature(this.camFrustum)] 8 | }); 9 | this.layer = new ol.layer.Vector({ 10 | source: featureVector, 11 | style: new ol.style.Style({ 12 | stroke: new ol.style.Stroke({ 13 | color: 'red', 14 | width: 2 15 | }) 16 | }) 17 | }); 18 | 19 | this.setColor = function(newColor) { 20 | this.layer.style.stroke.color = newColor; 21 | }; 22 | 23 | this.getExtent = function() { 24 | // var coordinates = this.camFrustum.getCoordinates(); 25 | // var leftBottom = new THREE.Vector3(coordinates[0][0], coordinates[0][1], 0); 26 | // var rightBottom = new THREE.Vector3(coordinates[1][0], coordinates[1][1], 0); 27 | // 28 | // var minx, miny, maxx, maxy; 29 | // 30 | // minx = leftBottom.x; 31 | // if (rightBottom.x < minx) { 32 | // minx = rightBottom.x; 33 | // } 34 | // maxx = leftBottom.x; 35 | // if (rightBottom.x > maxx) { 36 | // maxx = rightBottom.x; 37 | // } 38 | // miny = leftBottom.y; 39 | // if (rightBottom.y < miny) { 40 | // minx = rightBottom.y; 41 | // } 42 | // maxy = leftBottom.y; 43 | // if (rightBottom.y > maxy) { 44 | // maxy = rightBottom.y; 45 | // } 46 | // 47 | // return [minx, miny, maxx, maxy]; 48 | 49 | return featureVector.getExtent(); 50 | }; 51 | 52 | this.getCameraPosition = function() { 53 | var maxlength = 100 * 1000; 54 | 55 | var coordinates = this.camFrustum.getCoordinates(); 56 | var leftBottom = new THREE.Vector3(coordinates[0][0], coordinates[0][1], 0); 57 | var rightBottom = new THREE.Vector3(coordinates[1][0], coordinates[1][1], 0); 58 | var leftTop = new THREE.Vector3(coordinates[2][0], coordinates[2][1], 0); 59 | var rightTop = new THREE.Vector3(coordinates[3][0], coordinates[3][1], 0); 60 | 61 | var middleBottom = leftBottom.clone().lerp(rightBottom, 0.5); 62 | var middleTop = leftTop.clone().lerp(rightTop, 0.5); 63 | 64 | var dist = middleBottom.clone().sub(middleTop).length(); 65 | 66 | if (dist > maxlength) { 67 | dist = maxlength; 68 | } 69 | var frac = 1 - (dist / maxlength); 70 | 71 | var mapCameraPos = middleBottom.clone().lerp(middleTop, frac); 72 | return mapCameraPos.toArray().slice(0, 2); 73 | }; 74 | 75 | this.onCameraMove = function(frustum, floorInSight) { 76 | var frustumGeo = frustum.map(function(corner) { 77 | return [corner.x, corner.y]; 78 | }); 79 | 80 | if (floorInSight) { 81 | // solid line 82 | this.layer.getStyle().getStroke().setLineDash([]); 83 | } else { 84 | // dashed line 85 | this.layer.getStyle().getStroke().setLineDash([6]); 86 | } 87 | 88 | // polygon should be a ring so duplicate start to end of ring 89 | frustumGeo.push(frustumGeo[0]); 90 | 91 | this.camFrustum.setCoordinates(frustumGeo); 92 | }; 93 | } 94 | 95 | angular.module('pattyApp.minimap') 96 | .service('CamFrustumService', CamFrustumService); 97 | })(); 98 | -------------------------------------------------------------------------------- /app/scripts/minimap/minimap.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function pattyMinimap() { 5 | return { 6 | restrict: 'E', 7 | link: function(scope, element) { 8 | scope.vm.map.setTarget(element[0]); 9 | }, 10 | controller: 'MinimapController', 11 | controllerAs: 'vm' 12 | }; 13 | } 14 | 15 | angular.module('pattyApp.minimap') 16 | .directive('pattyMinimap', pattyMinimap); 17 | })(); 18 | -------------------------------------------------------------------------------- /app/scripts/pointcloud/pointcloud-canvas.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function PointcloudCanvasController(PointcloudService) { 5 | this.attachCanvas = function(el){ 6 | PointcloudService.attachCanvas(el); 7 | }; 8 | } 9 | 10 | angular.module('pattyApp.pointcloud') 11 | .controller('PointcloudCanvasController', PointcloudCanvasController); 12 | })(); 13 | -------------------------------------------------------------------------------- /app/scripts/pointcloud/pointcloud-canvas.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function pattyPointcloudCanvas() { 5 | return { 6 | restrict: 'E', 7 | link: function(scope, element) { 8 | scope.vm.attachCanvas(element[0]); 9 | }, 10 | controller: 'PointcloudCanvasController', 11 | controllerAs: 'vm' 12 | }; 13 | } 14 | 15 | angular.module('pattyApp.pointcloud') 16 | .directive('pattyPointcloudCanvas', pattyPointcloudCanvas); 17 | })(); 18 | -------------------------------------------------------------------------------- /app/scripts/pointcloud/pointcloud-stats.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function PointcloudStatsController(PointcloudService) { 5 | this.stats = PointcloudService.stats; 6 | this.PointcloudService = PointcloudService; 7 | this.settings = PointcloudService.settings; 8 | } 9 | 10 | angular.module('pattyApp.pointcloud') 11 | .controller('PointcloudStatsController', PointcloudStatsController); 12 | })(); 13 | -------------------------------------------------------------------------------- /app/scripts/pointcloud/pointcloud-stats.directive.html: -------------------------------------------------------------------------------- 1 |
2 |
Visible points: {{ pcs.stats.nrPoints }}
3 |
Visible nodes: {{ pcs.stats.nrNodes }}
4 |
3D Scene coordinates (x/y/z): {{ pcs.stats.sceneCoordinates.x }}/{{ pcs.stats.sceneCoordinates.y }}/{{ pcs.stats.sceneCoordinates.z }}
5 |
{{ pcs.stats.lasCoordinates.crs }} coordinates (x/y/z): {{ pcs.stats.lasCoordinates.x }}/{{ pcs.stats.lasCoordinates.y }}/{{ pcs.stats.lasCoordinates.z }}
6 |
7 | -------------------------------------------------------------------------------- /app/scripts/pointcloud/pointcloud-stats.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function pattyPointcloudStats() { 5 | return { 6 | restrict: 'E', 7 | templateUrl: 'scripts/pointcloud/pointcloud-stats.directive.html', 8 | controller: 'PointcloudStatsController', 9 | controllerAs: 'pcs' 10 | }; 11 | } 12 | 13 | angular.module('pattyApp.pointcloud') 14 | .directive('pattyPointcloudStats', pattyPointcloudStats); 15 | })(); 16 | -------------------------------------------------------------------------------- /app/scripts/pointcloud/scene.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function SceneService(THREE) { 5 | var scene = new THREE.Scene(); 6 | this.referenceFrame = new THREE.Object3D(); 7 | scene.add(this.referenceFrame); 8 | 9 | this.getScene = function() { 10 | return scene; 11 | }; 12 | 13 | /** 14 | * transform from geo coordinates to local scene coordinates 15 | * @param {THREE.Vector3} position With lon, lat, alt 16 | * @return {THREE.Vector3} with x, y, z 17 | */ 18 | this.toLocal = function(position) { 19 | var scenePos = position.clone().applyMatrix4(this.referenceFrame.matrixWorld); 20 | 21 | return scenePos; 22 | }; 23 | 24 | /** 25 | * transform from local scene coordinates to geo coordinates 26 | * @param {THREE.Vector3|THREE.Box3} object With lon, lat, alt 27 | * @return {THREE.Vector3|THREE.Box3} with x, y, z 28 | */ 29 | var reusableMatrix = new THREE.Matrix4(); 30 | var reusableBox = new THREE.Box3(); 31 | 32 | this.toGeo = function(object) { 33 | var geo; 34 | var inverse = reusableMatrix.identity().getInverse(this.referenceFrame.matrixWorld); 35 | 36 | if (object instanceof THREE.Vector3) { 37 | geo = object.clone().applyMatrix4(inverse); 38 | } else if (object instanceof THREE.Box3) { 39 | var geoMin = object.min.clone().applyMatrix4(inverse); 40 | var geoMax = object.max.clone().applyMatrix4(inverse); 41 | geo = reusableBox.set(geoMin, geoMax); 42 | } 43 | 44 | return geo; 45 | }; 46 | 47 | // this.addMaximap = function(mesh) { 48 | // MaximapService.addToMesh(mesh); 49 | // }; 50 | // 51 | // this.update = function() { 52 | // MaximapService.update(); 53 | // }; 54 | // 55 | // this.render = function() { 56 | // MaximapService.render(); 57 | // }; 58 | } 59 | 60 | angular.module('pattyApp.pointcloud') 61 | .service('SceneService', SceneService); 62 | })(); 63 | -------------------------------------------------------------------------------- /app/scripts/searchbox/searchbox.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function SearchPanelController(BingGeoCoderService, SceneService, PathControls, Messagebus, $window, toastr, THREE, proj4) { 5 | this.query = ''; 6 | this.hasGeoLocation = 'geolocation' in $window.navigator; 7 | 8 | this.clear = function() { 9 | this.query = ''; 10 | }; 11 | 12 | this.onLocationResponse = function(resources) { 13 | if (resources.length === 0) { 14 | toastr.warning('No results', 'Location not found'); 15 | return; 16 | } 17 | var resource = resources[0]; 18 | this.query = resource.name.replace(', Nederland', ''); 19 | var location = resource.point.coordinates; 20 | this.gotoLocation(location[1], location[0]); 21 | }; 22 | 23 | this.search = function() { 24 | BingGeoCoderService.geocode(this.query).then( 25 | this.onLocationResponse.bind(this), 26 | function() { 27 | toastr.error('Search failed', 'for some reason'); 28 | } 29 | ); 30 | }; 31 | 32 | /** 33 | * When enter is pressed inside input field perform a search 34 | */ 35 | this.onQueryKeyPress = function($event) { 36 | var enterCode = 13; 37 | if ($event.keyCode === enterCode) { 38 | this.search(); 39 | } 40 | }; 41 | 42 | this.gotoLocation = function(longitude, latitude) { 43 | var altitude = 0; 44 | var bingProjection = 'EPSG:4326'; 45 | var bingLocation = [longitude, latitude]; 46 | var nlProjection = 'EPSG:28992'; 47 | 48 | // look at location 49 | var geoLocation = proj4(bingProjection, nlProjection, bingLocation); 50 | var geoVector = new THREE.Vector3(geoLocation[0], geoLocation[1], altitude); 51 | var sceneLocation = SceneService.toLocal(geoVector); 52 | 53 | // move camera to location 54 | var moveOffsetX = 0; 55 | var moveOffsetY = -1000; 56 | var moveOffsetZ = 1000; 57 | var geoLocationMove = [geoLocation[0] + moveOffsetX, geoLocation[1] + moveOffsetY]; 58 | var sceneLocationMove = SceneService.toLocal(new THREE.Vector3(geoLocationMove[0], geoLocationMove[1], altitude + moveOffsetZ)); 59 | 60 | PathControls.moveTo(sceneLocationMove); 61 | PathControls.lookat(sceneLocation); 62 | }; 63 | 64 | this.gotoCurrentLocation = function() { 65 | $window.navigator.geolocation.getCurrentPosition(function(position) { 66 | var c = position.coords; 67 | this.gotoLocation(c.longitude, c.latitude); 68 | }.bind(this), function() { 69 | toastr.error('Unable to get current location'); 70 | }); 71 | }; 72 | } 73 | 74 | angular.module('pattyApp.searchbox') 75 | .controller('SearchPanelController', SearchPanelController); 76 | })(); 77 | -------------------------------------------------------------------------------- /app/scripts/searchbox/searchbox.directive.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | -------------------------------------------------------------------------------- /app/scripts/searchbox/searchbox.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function pattySearchPanel() { 5 | return { 6 | restrict: 'E', 7 | templateUrl: 'scripts/searchbox/searchbox.directive.html', 8 | controller: 'SearchPanelController', 9 | controllerAs: 'sp' 10 | }; 11 | } 12 | 13 | angular.module('pattyApp.searchbox') 14 | .directive('pattySearchPanel', pattySearchPanel); 15 | })(); 16 | -------------------------------------------------------------------------------- /app/scripts/settings/settings.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function SettingsController(PointcloudService, MeasuringService, Messagebus, PathControls, RailService) { 5 | this.showSettings = false; 6 | // this.predefinedSettings = PointcloudService.predefinedSettings; 7 | // this.settings = PointcloudService.settings; 8 | this.PointcloudService = PointcloudService; 9 | this.PathControls = PathControls; 10 | this.RailService = RailService; 11 | this.measure = MeasuringService; 12 | 13 | this.ld = false; 14 | this.sd = true; 15 | this.md = false; 16 | this.hd = false; 17 | 18 | this.toggleSettings = function() { 19 | if (!this.showSettings) { 20 | Messagebus.publish('closeOtherPanels', 'settings'); 21 | 22 | this.showSettings = true; 23 | } else { 24 | this.showSettings = false; 25 | } 26 | }; 27 | 28 | this.panelClose = function(event, panelNameToRemainOpen) { 29 | if (panelNameToRemainOpen !== 'settings') { 30 | this.showSettings = false; 31 | } 32 | }.bind(this); 33 | 34 | Messagebus.subscribe('closeOtherPanels', this.panelClose); 35 | 36 | this.settingsChanged = function() { 37 | this.ld = false; 38 | this.sd = false; 39 | this.md = false; 40 | this.hd = false; 41 | if (this.PointcloudService.settings === this.PointcloudService.predefinedSettings.LOW) { 42 | this.ld=true; 43 | } else if (this.PointcloudService.settings === this.PointcloudService.predefinedSettings.STANDARD) { 44 | this.sd=true; 45 | } else if (this.PointcloudService.settings === this.PointcloudService.predefinedSettings.HIGH) { 46 | this.md=true; 47 | } else if (this.PointcloudService.settings === this.PointcloudService.predefinedSettings.ULTRA) { 48 | this.hd=true; 49 | } 50 | }.bind(this); 51 | } 52 | 53 | angular.module('pattyApp.settings').controller('SettingsController', SettingsController); 54 | })(); 55 | -------------------------------------------------------------------------------- /app/scripts/settings/settings.directive.html: -------------------------------------------------------------------------------- 1 |