27 |
28 |
29 |
--------------------------------------------------------------------------------
/test/util/create-canvas.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 | define(function(require) {
3 | 'use strict';
4 |
5 | var defaultValue = require('Cesium/Core/defaultValue');
6 |
7 | var canvasCount = 0;
8 |
9 | return function createCanvas(width, height) {
10 | width = defaultValue(width, 1);
11 | height = defaultValue(height, 1);
12 |
13 | var canvas = document.createElement('canvas');
14 | canvas.id = 'canvas' + canvasCount++;
15 | canvas.setAttribute('width', width);
16 | canvas.setAttribute('clientWidth', width);
17 | canvas.setAttribute('height', height);
18 | canvas.setAttribute('clientHeight', height);
19 | canvas.innerHTML = 'To view this web page, upgrade your browser; it does not support the HTML5 canvas element.';
20 | document.body.appendChild(canvas);
21 |
22 | return canvas;
23 | };
24 | });
25 |
--------------------------------------------------------------------------------
/lib/copyright-header.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Cesium Sensor Volumes - https://github.com/jlouns/cesium-sensor-volumes
3 | *
4 | * Copyright 2016 Jonathan Lounsbury
5 | * Copyright 2011-2014 Analytical Graphics Inc. and Cesium Contributors
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | * Portions licensed separately.
20 | * See https://github.com/jlouns/cesium-sensor-volumes/blob/master/LICENSE.md for full licensing details.
21 | *
22 | * Derived from Cesium Sensors - https://github.com/AnalyticalGraphicsInc/cesium-sensors
23 | */
24 |
--------------------------------------------------------------------------------
/test/initialize-webgl-spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-nested-callbacks */
2 | define([
3 | 'Cesium/DataSources/CzmlDataSource',
4 | 'Cesium/DataSources/DataSourceCollection',
5 | 'Cesium/DataSources/DataSourceDisplay',
6 | 'initialize',
7 | './util/create-scene'
8 | ], function(
9 | CzmlDataSource,
10 | DataSourceCollection,
11 | DataSourceDisplay,
12 | initialize,
13 | createScene
14 | ) {
15 | 'use strict';
16 |
17 | /* global describe, it, beforeAll, afterAll */
18 |
19 | describe('initialize', function() {
20 | var scene;
21 |
22 | beforeAll(function() {
23 | scene = createScene();
24 | });
25 |
26 | afterAll(function() {
27 | scene.destroyForSpecs();
28 | });
29 |
30 | it('should create a data source collection', function() {
31 | initialize();
32 |
33 | var dataSourceCollection = new DataSourceCollection();
34 |
35 | // eslint-disable-next-line no-new
36 | new DataSourceDisplay({
37 | scene: scene,
38 | dataSourceCollection: dataSourceCollection
39 | });
40 |
41 | dataSourceCollection.add(new CzmlDataSource());
42 | });
43 | });
44 | }, 'WebGL');
45 |
--------------------------------------------------------------------------------
/gulp/generate-shims.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gutil = require('gulp-util');
4 | var pluginStream = require('./plugin-stream');
5 |
6 | var PLUGIN_NAME = 'cesium-sensors-generate-shims';
7 |
8 | module.exports = function() {
9 | var shims = {};
10 |
11 | return pluginStream(PLUGIN_NAME, function(file, enc, cb) {
12 | var contents = file.contents.toString();
13 | // Search for Cesium modules and add shim
14 | // modules that pull from the Cesium global
15 |
16 | var cesiumRequireRegex = /'Cesium\/\w*\/(\w*)'/g;
17 | var match;
18 | while ((match = cesiumRequireRegex.exec(contents)) !== null) {
19 | if (match[0] in shims) {
20 | continue;
21 | }
22 |
23 | shims[match[0]] = 'define(' + match[0] + ', function() { return Cesium[\'' + match[1] + '\']; });';
24 | }
25 |
26 | cb();
27 | }, function(cb) {
28 | var shimContents = Object.keys(shims).map(function(key) {
29 | return shims[key];
30 | }).join('\n');
31 |
32 | shimContents = '\'use strict\';\n' +
33 | '/* global Cesium */\n' +
34 | shimContents;
35 |
36 | this.push(new gutil.File({
37 | path: 'cesium-shims.js',
38 | contents: Buffer.from(shimContents)
39 | }));
40 |
41 | cb();
42 | });
43 | };
44 |
--------------------------------------------------------------------------------
/test/spec-main.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 | 'use strict';
3 |
4 | var allTestFiles = [];
5 | var TEST_REGEXP = /^\/base\/test\/.*(spec)\.js$/;
6 | var WEBGL_REGEXP = /webgl/;
7 |
8 | function pathToModule(path) {
9 | return path.replace(/^\/base\//, '').replace(/\.js$/, '');
10 | }
11 |
12 | var excludeWebGl = false;
13 | if (window.__karma__.config.args) {
14 | excludeWebGl = window.__karma__.config.args[0];
15 | }
16 |
17 | Object.keys(window.__karma__.files).forEach(function(file) {
18 | if (TEST_REGEXP.test(file)) {
19 | // exclude WebGL tests
20 | if (!excludeWebGl || !WEBGL_REGEXP.test(file)) {
21 | // Normalize paths to RequireJS module names.
22 | allTestFiles.push(pathToModule(file));
23 | }
24 | }
25 | });
26 |
27 | require.config({
28 | // Karma serves files under /base, which is the basePath from your config file
29 | baseUrl: '/base/lib',
30 |
31 | paths: {
32 | Cesium: '../node_modules/cesium/Source',
33 |
34 | text: '../node_modules/requirejs-text/text',
35 |
36 | test: '../test'
37 | },
38 |
39 | // dynamically load all test files
40 | deps: allTestFiles,
41 |
42 | // we have to kickoff jasmine, as it is asynchronous
43 | callback: window.__karma__.start
44 | });
45 |
--------------------------------------------------------------------------------
/test/matchers/make-throw-function.js:
--------------------------------------------------------------------------------
1 | define(function() {
2 | 'use strict';
3 |
4 | return function makeThrowFunction(debug, Type, name) {
5 | if (debug) {
6 | return function() {
7 | return {
8 | compare: function(actual) {
9 | // based on the built-in Jasmine toThrow matcher
10 | var result = false;
11 | var exception;
12 |
13 | if (typeof actual !== 'function') {
14 | throw new TypeError('Actual is not a function');
15 | }
16 |
17 | try {
18 | actual();
19 | } catch (err) {
20 | exception = err;
21 | }
22 |
23 | if (exception) {
24 | result = exception instanceof Type;
25 | }
26 |
27 | var message;
28 | if (result) {
29 | message = ['Expected function not to throw ' + name + ' , but it threw', exception.message || exception].join(' ');
30 | } else {
31 | message = 'Expected function to throw ' + name + '.';
32 | }
33 |
34 | return {
35 | pass: result,
36 | message: message
37 | };
38 | }
39 | };
40 | };
41 | }
42 |
43 | return function() {
44 | return {
45 | compare: function() {
46 | return { pass: true };
47 | },
48 | negativeCompare: function() {
49 | return { pass: true };
50 | }
51 | };
52 | };
53 | };
54 | });
55 |
--------------------------------------------------------------------------------
/lib/cesium-sensor-volumes.js:
--------------------------------------------------------------------------------
1 | define(function(require) {
2 | 'use strict';
3 |
4 | var initialize = require('./initialize');
5 | var ConicSensorGraphics = require('./conic/conic-sensor-graphics');
6 | var ConicSensorVisualizer = require('./conic/conic-sensor-visualizer');
7 | var CustomPatternSensorGraphics = require('./custom/custom-pattern-sensor-graphics');
8 | var CustomPatternSensorVisualizer = require('./custom/custom-pattern-sensor-visualizer');
9 | var CustomSensorVolume = require('./custom/custom-sensor-volume');
10 | var RectangularPyramidSensorVolume = require('./rectangular/rectangular-pyramid-sensor-volume');
11 | var RectangularSensorGraphics = require('./rectangular/rectangular-sensor-graphics');
12 | var RectangularSensorVisualizer = require('./rectangular/rectangular-sensor-visualizer');
13 |
14 | initialize();
15 |
16 | return {
17 | ConicSensorGraphics: ConicSensorGraphics,
18 | ConicSensorVisualizer: ConicSensorVisualizer,
19 | CustomPatternSensorGraphics: CustomPatternSensorGraphics,
20 | CustomPatternSensorVisualizer: CustomPatternSensorVisualizer,
21 | CustomSensorVolume: CustomSensorVolume,
22 | RectangularPyramidSensorVolume: RectangularPyramidSensorVolume,
23 | RectangularSensorGraphics: RectangularSensorGraphics,
24 | RectangularSensorVisualizer: RectangularSensorVisualizer
25 | };
26 | });
27 |
--------------------------------------------------------------------------------
/lib/sensor-volume.glsl:
--------------------------------------------------------------------------------
1 | uniform vec4 u_intersectionColor;
2 | uniform float u_intersectionWidth;
3 |
4 | bool inSensorShadow(vec3 coneVertexWC, czm_ellipsoid ellipsoidEC, vec3 pointWC)
5 | {
6 | // Diagonal matrix from the unscaled ellipsoid space to the scaled space.
7 | vec3 D = ellipsoidEC.inverseRadii;
8 |
9 | // Sensor vertex in the scaled ellipsoid space
10 | vec3 q = D * coneVertexWC;
11 | float qMagnitudeSquared = dot(q, q);
12 | float test = qMagnitudeSquared - 1.0;
13 |
14 | // Sensor vertex to fragment vector in the ellipsoid's scaled space
15 | vec3 temp = D * pointWC - q;
16 | float d = dot(temp, q);
17 |
18 | // Behind silhouette plane and inside silhouette cone
19 | return (d < -test) && (d / length(temp) < -sqrt(test));
20 | }
21 |
22 | ///////////////////////////////////////////////////////////////////////////////
23 |
24 | vec4 getIntersectionColor()
25 | {
26 | return u_intersectionColor;
27 | }
28 |
29 | float getIntersectionWidth()
30 | {
31 | return u_intersectionWidth;
32 | }
33 |
34 | vec2 sensor2dTextureCoordinates(float sensorRadius, vec3 pointMC)
35 | {
36 | // (s, t) both in the range [0, 1]
37 | float t = pointMC.z / sensorRadius;
38 | float s = 1.0 + (atan(pointMC.y, pointMC.x) / czm_twoPi);
39 | s = s - floor(s);
40 |
41 | return vec2(s, t);
42 | }
43 |
--------------------------------------------------------------------------------
/examples/czml.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Cesium Sensor Volumes Example
11 |
12 |
13 |
14 |
15 |
16 |
40 |
41 |
42 |
43 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/test/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 | 'use strict';
3 | config.set({
4 |
5 | // base path that will be used to resolve all patterns (eg. files, exclude)
6 | basePath: '../',
7 |
8 | // frameworks to use
9 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
10 | frameworks: ['jasmine', 'requirejs'],
11 |
12 | // list of files / patterns to load in the browser
13 | files: [
14 | 'test/spec-main.js',
15 | { pattern: 'node_modules/cesium/Source/**/*', included: false },
16 | { pattern: 'node_modules/requirejs-text/*.js', included: false },
17 | { pattern: 'lib/**/*.js', included: false },
18 | { pattern: 'lib/**/*.glsl', included: false },
19 | { pattern: 'test/**/*.js', included: false }
20 | ],
21 |
22 | // list of files to exclude
23 | exclude: [
24 | 'lib/main.js'
25 | ],
26 |
27 | preprocessors: {
28 | 'lib/**/*.js': ['coverage']
29 | },
30 |
31 | // test results reporter to use
32 | // possible values: 'dots', 'progress'
33 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
34 | reporters: ['progress', 'coverage'],
35 |
36 | junitReporter: {
37 | outputFile: 'spec_out/unit.xml',
38 | suite: 'unit'
39 | },
40 |
41 | // web server port
42 | port: 9876,
43 |
44 | // enable / disable colors in the output (reporters and logs)
45 | colors: true,
46 |
47 | // level of logging
48 | logLevel: config.LOG_INFO,
49 |
50 | // enable / disable watching file and executing tests whenever any file changes
51 | autoWatch: true,
52 |
53 | // start these browsers
54 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
55 | browsers: ['Chrome'],
56 |
57 | // Continuous Integration mode
58 | // if true, Karma captures browsers, runs the tests and exits
59 | singleRun: false
60 | });
61 | };
62 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | This plugin is based on the cesium-sensors plugin by Analytical Graphics Inc. and Cesium Contributors: https://github.com/AnalyticalGraphicsInc/cesium-sensors
2 |
3 | Copyright 2016 Jonathan Lounsbury
4 | Copyright 2011-2014 Analytical Graphics Inc. and Cesium Contributors
5 |
6 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 |
12 | Third-Party Code
13 | ================
14 |
15 | cesium-sensor-volumes includes the following third-party code.
16 |
17 | ### almond
18 |
19 | https://github.com/jrburke/almond
20 |
21 | > Copyright (c) 2010-2011, The Dojo Foundation
22 | >
23 | > Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
24 | >
25 | > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
26 | >
27 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 |
29 |
--------------------------------------------------------------------------------
/gulp/process-shaders.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gutil = require('gulp-util');
4 | var pluginStream = require('./plugin-stream');
5 |
6 | var PLUGIN_NAME = 'cesium-sensors-process-shaders';
7 |
8 | module.exports = function() {
9 | var shaderLicenseComments = [];
10 |
11 | return pluginStream(PLUGIN_NAME, function(file, enc, cb) {
12 | var contents = file.contents.toString();
13 | contents = contents.replace(/\r\n/gm, '\n');
14 |
15 | // eslint-disable-next-line no-useless-escape
16 | var licenseComments = contents.match(/\/\*\*(?:[^*\/]|\*(?!\/)|\n)*?@license(?:.|\n)*?\*\//gm);
17 | if (licenseComments !== null) {
18 | shaderLicenseComments = shaderLicenseComments.concat(licenseComments);
19 | }
20 |
21 | var newContents = [];
22 | // Remove comments. Code ported from
23 | // https://github.com/apache/ant/blob/master/src/main/org/apache/tools/ant/filters/StripJavaComments.java
24 | for (var i = 0; i < contents.length; ++i) {
25 | var c = contents.charAt(i);
26 | if (c === '/') {
27 | c = contents.charAt(++i);
28 | if (c === '/') {
29 | while (c !== '\r' && c !== '\n' && i < contents.length) {
30 | c = contents.charAt(++i);
31 | }
32 | } else if (c === '*') {
33 | while (i < contents.length) {
34 | c = contents.charAt(++i);
35 | if (c === '*') {
36 | c = contents.charAt(++i);
37 | while (c === '*') {
38 | c = contents.charAt(++i);
39 | }
40 | if (c === '/') {
41 | c = contents.charAt(++i);
42 | break;
43 | }
44 | }
45 | }
46 | } else {
47 | --i;
48 | c = '/';
49 | }
50 | }
51 | newContents.push(c);
52 | }
53 |
54 | newContents = newContents.join('');
55 | newContents = newContents.replace(/\s+$/gm, '').replace(/^\s+/gm, '').replace(/\n+/gm, '\n');
56 |
57 | cb(null, new gutil.File({
58 | path: file.relative,
59 | contents: Buffer.from(newContents)
60 | }));
61 | }, function(cb) {
62 | this.push(new gutil.File({
63 | path: 'shader-copyright-header.js',
64 | contents: Buffer.from(shaderLicenseComments.join('\n'))
65 | }));
66 | cb();
67 | });
68 | };
69 |
--------------------------------------------------------------------------------
/test/util/create-scene.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 | define(function(require) {
3 | 'use strict';
4 |
5 | var Cartesian2 = require('Cesium/Core/Cartesian2');
6 | var clone = require('Cesium/Core/clone');
7 | var defaultValue = require('Cesium/Core/defaultValue');
8 | var defined = require('Cesium/Core/defined');
9 | var queryToObject = require('Cesium/Core/queryToObject');
10 | var Scene = require('Cesium/Scene/Scene');
11 | var createCanvas = require('./create-canvas');
12 | var destroyCanvas = require('./destroy-canvas');
13 |
14 | return function createScene(options) {
15 | options = defaultValue(options, {});
16 |
17 | // save the canvas so we don't try to clone an HTMLCanvasElement
18 | var canvas = defined(options.canvas) ? options.canvas : createCanvas();
19 | options.canvas = undefined;
20 |
21 | options = clone(options, true);
22 |
23 | options.canvas = canvas;
24 | options.contextOptions = defaultValue(options.contextOptions, {});
25 |
26 | var contextOptions = options.contextOptions;
27 | contextOptions.webgl = defaultValue(contextOptions.webgl, {});
28 | contextOptions.webgl.antialias = defaultValue(contextOptions.webgl.antialias, false);
29 |
30 | var scene = new Scene(options);
31 |
32 | var parameters = queryToObject(window.location.search.substring(1));
33 | if (defined(parameters.webglValidation)) {
34 | var context = scene.context;
35 | context.validateShaderProgram = true;
36 | context.validateFramebuffer = true;
37 | context.logShaderCompilation = true;
38 | context.throwOnWebGLError = true;
39 | }
40 |
41 | // Add functions for test
42 | scene.destroyForSpecs = function() {
43 | var canvas = scene.canvas;
44 | scene.destroy();
45 | destroyCanvas(canvas);
46 | };
47 |
48 | scene.renderForSpecs = function(time) {
49 | scene.initializeFrame();
50 | scene.render(time);
51 | return scene.context.readPixels();
52 | };
53 |
54 | scene.pickForSpecs = function() {
55 | return scene.pick(new Cartesian2(0, 0));
56 | };
57 |
58 | scene.rethrowRenderErrors = defaultValue(options.rethrowRenderErrors, true);
59 |
60 | return scene;
61 | };
62 | });
63 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cesium-sensor-volumes",
3 | "version": "1.32.0",
4 | "description": "A Cesium plugin for visualizing sensor volumes.",
5 | "homepage": "https://cesiumjs.org",
6 | "license": "Apache-2.0",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/jlouns/cesium-sensor-volumes.git"
10 | },
11 | "keywords": [
12 | "cesium"
13 | ],
14 | "dependencies": {
15 | "cesium": "1.32.1",
16 | "requirejs": "^2.3.3",
17 | "requirejs-text": "^2.0.15"
18 | },
19 | "devDependencies": {
20 | "almond": "^0.3.3",
21 | "browser-sync": "^2.18.8",
22 | "del": "^2.2.2",
23 | "electron": "1.6.5",
24 | "event-stream": "^3.3.4",
25 | "globby": "^6.1.0",
26 | "gulp": "^3.9.0",
27 | "gulp-concat": "^2.6.1",
28 | "gulp-if": "^2.0.2",
29 | "gulp-order": "^1.1.1",
30 | "gulp-requirejs-optimize": "^1.2.0",
31 | "gulp-size": "^2.0.0",
32 | "gulp-util": "^3.0.8",
33 | "gulp-xo": "^0.15.0",
34 | "jasmine-core": "^2.5.2",
35 | "karma": "^1.6.0",
36 | "karma-chrome-launcher": "^2.0.0",
37 | "karma-coverage": "^1.1.1",
38 | "karma-electron-launcher": "^0.2.0",
39 | "karma-jasmine": "^1.1.0",
40 | "karma-requirejs": "^1.1.0",
41 | "lodash.assign": "^4.2.0",
42 | "merge-stream": "^1.0.1",
43 | "run-sequence": "^1.2.2",
44 | "through2": "^2.0.3"
45 | },
46 | "scripts": {
47 | "build": "gulp build",
48 | "start": "gulp serve",
49 | "test": "gulp test",
50 | "ci": "gulp ci"
51 | },
52 | "xo": {
53 | "globals": [
54 | "define"
55 | ],
56 | "esnext": false,
57 | "rules": {
58 | "capitalized-comments": "off",
59 | "func-names": "off",
60 | "import/no-amd": "off",
61 | "import/no-extraneous-dependencies": "off",
62 | "import/no-unresolved": "off",
63 | "import/no-webpack-loader-syntax": "off",
64 | "object-curly-spacing": [
65 | "error",
66 | "always",
67 | {
68 | "objectsInObjects": false,
69 | "arraysInObjects": false
70 | }
71 | ],
72 | "space-before-function-paren": [
73 | "error",
74 | "never"
75 | ]
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [cesium](https://cesiumjs.org)-sensor-volumes
2 | [](https://travis-ci.org/jlouns/cesium-sensor-volumes)
3 | [](https://badge.fury.io/js/cesium-sensor-volumes)
4 | [](https://david-dm.org/jlouns/cesium-sensor-volumes)
5 | [](http://www.apache.org/licenses/LICENSE-2.0.html)
6 |
7 | A Cesium plugin for visualizing sensor volumes. Based on [cesium-sensors](https://github.com/AnalyticalGraphicsInc/cesium-sensors) and evolved to support more recent Cesium versions.
8 |
9 | ## Install
10 |
11 | ```sh
12 | $ npm install --save cesium-sensor-volumes
13 | ```
14 |
15 | ## Usage
16 |
17 | Prebuilt minified and unminified versions of the plugin are in the [dist](dist/) directory. Include the `cesium-sensor-volumes.js` file using a `script` tag after the `Cesium.js` `script` tag.
18 |
19 | The plugin automatically adds support for the CZML properties `agi_conicSensor`, `agi_customPatternSensor`, and `agi_rectangularSensor`. The corresponding `Entity` properties are `conicSensor`, `customPatternSensor`, and `rectangularSensor`.
20 |
21 | In order to load data directly into `Entity` objects that you create directly, you must call `entity.addProperty` to create each of the sensor properties you wish to use. The CZML processing does this automatically.
22 |
23 | ```html
24 |
25 |
26 |
38 | ```
39 |
40 | ### Examples
41 |
42 | Simple examples are included in the [examples](examples/) folder. To run locally, run `npm start` and navigate to [http://localhost:3000](http://localhost:3000) and select the example application to run.
43 |
44 | ## Build
45 |
46 | To build, run `npm install`, then run `npm run build`.
47 |
48 | ## License
49 |
50 | Apache 2.0. Free for commercial and non-commercial use. See [LICENSE.md](LICENSE.md).
51 |
--------------------------------------------------------------------------------
/lib/custom/custom-sensor-volume-fs.glsl:
--------------------------------------------------------------------------------
1 | #ifdef GL_OES_standard_derivatives
2 | #extension GL_OES_standard_derivatives : enable
3 | #endif
4 |
5 | uniform bool u_showIntersection;
6 | uniform bool u_showThroughEllipsoid;
7 |
8 | uniform float u_sensorRadius;
9 | uniform float u_normalDirection;
10 |
11 | varying vec3 v_positionWC;
12 | varying vec3 v_positionEC;
13 | varying vec3 v_normalEC;
14 |
15 | vec4 getColor(float sensorRadius, vec3 pointEC)
16 | {
17 | czm_materialInput materialInput;
18 |
19 | vec3 pointMC = (czm_inverseModelView * vec4(pointEC, 1.0)).xyz;
20 | materialInput.st = sensor2dTextureCoordinates(sensorRadius, pointMC);
21 | materialInput.str = pointMC / sensorRadius;
22 |
23 | vec3 positionToEyeEC = -v_positionEC;
24 | materialInput.positionToEyeEC = positionToEyeEC;
25 |
26 | vec3 normalEC = normalize(v_normalEC);
27 | materialInput.normalEC = u_normalDirection * normalEC;
28 |
29 | czm_material material = czm_getMaterial(materialInput);
30 | return mix(czm_phong(normalize(positionToEyeEC), material), vec4(material.diffuse, material.alpha), 0.4);
31 | }
32 |
33 | bool isOnBoundary(float value, float epsilon)
34 | {
35 | float width = getIntersectionWidth();
36 | float tolerance = width * epsilon;
37 |
38 | #ifdef GL_OES_standard_derivatives
39 | float delta = max(abs(dFdx(value)), abs(dFdy(value)));
40 | float pixels = width * delta;
41 | float temp = abs(value);
42 | // There are a couple things going on here.
43 | // First we test the value at the current fragment to see if it is within the tolerance.
44 | // We also want to check if the value of an adjacent pixel is within the tolerance,
45 | // but we don't want to admit points that are obviously not on the surface.
46 | // For example, if we are looking for "value" to be close to 0, but value is 1 and the adjacent value is 2,
47 | // then the delta would be 1 and "temp - delta" would be "1 - 1" which is zero even though neither of
48 | // the points is close to zero.
49 | return temp < tolerance && temp < pixels || (delta < 10.0 * tolerance && temp - delta < tolerance && temp < pixels);
50 | #else
51 | return abs(value) < tolerance;
52 | #endif
53 | }
54 |
55 | vec4 shade(bool isOnBoundary)
56 | {
57 | if (u_showIntersection && isOnBoundary)
58 | {
59 | return getIntersectionColor();
60 | }
61 | return getColor(u_sensorRadius, v_positionEC);
62 | }
63 |
64 | float ellipsoidSurfaceFunction(czm_ellipsoid ellipsoid, vec3 point)
65 | {
66 | vec3 scaled = ellipsoid.inverseRadii * point;
67 | return dot(scaled, scaled) - 1.0;
68 | }
69 |
70 | void main()
71 | {
72 | vec3 sensorVertexWC = czm_model[3].xyz; // (0.0, 0.0, 0.0) in model coordinates
73 | vec3 sensorVertexEC = czm_modelView[3].xyz; // (0.0, 0.0, 0.0) in model coordinates
74 |
75 | czm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC();
76 | float ellipsoidValue = ellipsoidSurfaceFunction(ellipsoid, v_positionWC);
77 |
78 | // Occluded by the ellipsoid?
79 | if (!u_showThroughEllipsoid)
80 | {
81 | // Discard if in the ellipsoid
82 | // PERFORMANCE_IDEA: A coarse check for ellipsoid intersection could be done on the CPU first.
83 | if (ellipsoidValue < 0.0)
84 | {
85 | discard;
86 | }
87 |
88 | // Discard if in the sensor's shadow
89 | if (inSensorShadow(sensorVertexWC, ellipsoid, v_positionWC))
90 | {
91 | discard;
92 | }
93 | }
94 |
95 | // Discard if not in the sensor's sphere
96 | // PERFORMANCE_IDEA: We can omit this check if the radius is Number.POSITIVE_INFINITY.
97 | if (distance(v_positionEC, sensorVertexEC) > u_sensorRadius)
98 | {
99 | discard;
100 | }
101 |
102 | // Notes: Each surface functions should have an associated tolerance based on the floating point error.
103 | bool isOnEllipsoid = isOnBoundary(ellipsoidValue, czm_epsilon3);
104 | gl_FragColor = shade(isOnEllipsoid);
105 | }
106 |
--------------------------------------------------------------------------------
/examples/api.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Cesium Sensor Volumes Example
11 |
12 |
13 |
14 |
15 |
16 |
46 |
47 |
48 |
49 |
50 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/test/custom/custom-pattern-sensor-graphics-spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-nested-callbacks */
2 | define([
3 | 'custom/custom-pattern-sensor-graphics',
4 | 'Cesium/Core/Color',
5 | 'Cesium/DataSources/ColorMaterialProperty',
6 | 'Cesium/DataSources/ConstantProperty',
7 | '../matchers/add-to-throw-developer-error-matcher'
8 | ], function(
9 | CustomPatternSensorGraphics,
10 | Color,
11 | ColorMaterialProperty,
12 | ConstantProperty,
13 | addToThrowDeveloperErrorMatcher
14 | ) {
15 | 'use strict';
16 |
17 | /* global describe, it, beforeEach, expect */
18 |
19 | describe('custom pattern sensor graphics', function() {
20 | describe('merge', function() {
21 | beforeEach(addToThrowDeveloperErrorMatcher);
22 |
23 | it('should assign unassigned properties', function() {
24 | var source = new CustomPatternSensorGraphics();
25 | source.lateralSurfaceMaterial = new ColorMaterialProperty();
26 | source.directions = new ConstantProperty([]);
27 | source.intersectionColor = new ConstantProperty(Color.WHITE);
28 | source.radius = new ConstantProperty(1);
29 | source.show = new ConstantProperty(true);
30 | source.showIntersection = new ConstantProperty(true);
31 | source.intersectionWidth = new ConstantProperty(1);
32 |
33 | var target = new CustomPatternSensorGraphics();
34 | target.merge(source);
35 |
36 | expect(target.lateralSurfaceMaterial).toBe(source.lateralSurfaceMaterial);
37 | expect(target.directions).toBe(source.directions);
38 | expect(target.intersectionColor).toBe(source.intersectionColor);
39 | expect(target.radius).toBe(source.radius);
40 | expect(target.show).toBe(source.show);
41 | expect(target.showIntersection).toBe(source.showIntersection);
42 | expect(target.intersectionWidth).toBe(source.intersectionWidth);
43 | });
44 |
45 | it('should not assign assigned properties', function() {
46 | var source = new CustomPatternSensorGraphics();
47 | source.lateralSurfaceMaterial = new ColorMaterialProperty();
48 | source.directions = new ConstantProperty([]);
49 | source.intersectionColor = new ConstantProperty(Color.WHITE);
50 | source.radius = new ConstantProperty(1);
51 | source.show = new ConstantProperty(true);
52 | source.showIntersection = new ConstantProperty(true);
53 | source.intersectionWidth = new ConstantProperty(1);
54 |
55 | var lateralSurfaceMaterial = new ColorMaterialProperty();
56 | var directions = new ConstantProperty([]);
57 | var intersectionColor = new ConstantProperty(Color.WHITE);
58 | var radius = new ConstantProperty(1);
59 | var show = new ConstantProperty(true);
60 | var showIntersection = new ConstantProperty(true);
61 | var intersectionWidth = new ConstantProperty(1);
62 |
63 | var target = new CustomPatternSensorGraphics();
64 | target.lateralSurfaceMaterial = lateralSurfaceMaterial;
65 | target.directions = directions;
66 | target.intersectionColor = intersectionColor;
67 | target.radius = radius;
68 | target.show = show;
69 | target.showIntersection = showIntersection;
70 | target.intersectionWidth = intersectionWidth;
71 |
72 | target.merge(source);
73 |
74 | expect(target.lateralSurfaceMaterial).toBe(lateralSurfaceMaterial);
75 | expect(target.directions).toBe(directions);
76 | expect(target.intersectionColor).toBe(intersectionColor);
77 | expect(target.radius).toBe(radius);
78 | expect(target.show).toBe(show);
79 | expect(target.showIntersection).toBe(showIntersection);
80 | expect(target.intersectionWidth).toBe(intersectionWidth);
81 | });
82 |
83 | it('should throw if source undefined', function() {
84 | var target = new CustomPatternSensorGraphics();
85 | expect(function() {
86 | target.merge(undefined);
87 | }).toThrowDeveloperError();
88 | });
89 | });
90 |
91 | it('should clone', function() {
92 | var source = new CustomPatternSensorGraphics();
93 | source.lateralSurfaceMaterial = new ColorMaterialProperty();
94 | source.directions = new ConstantProperty([]);
95 | source.intersectionColor = new ConstantProperty(Color.WHITE);
96 | source.radius = new ConstantProperty(1);
97 | source.show = new ConstantProperty(true);
98 | source.showIntersection = new ConstantProperty(true);
99 | source.intersectionWidth = new ConstantProperty(1);
100 |
101 | var result = source.clone();
102 | expect(result.lateralSurfaceMaterial).toBe(source.lateralSurfaceMaterial);
103 | expect(result.directions).toBe(source.directions);
104 | expect(result.intersectionColor).toBe(source.intersectionColor);
105 | expect(result.radius).toBe(source.radius);
106 | expect(result.show).toBe(source.show);
107 | expect(result.showIntersection).toBe(source.showIntersection);
108 | expect(result.intersectionWidth).toBe(source.intersectionWidth);
109 | });
110 | });
111 | });
112 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var path = require('path');
5 |
6 | var es = require('event-stream');
7 | var globby = require('globby');
8 | var gulp = require('gulp');
9 | var assign = require('lodash.assign');
10 |
11 | // load plugins
12 | var browserSync = require('browser-sync').create();
13 | var concat = require('gulp-concat');
14 | var del = require('del');
15 | var gulpif = require('gulp-if');
16 | var order = require('gulp-order');
17 | var requirejsOptimize = require('gulp-requirejs-optimize');
18 | var runSequence = require('run-sequence');
19 | var size = require('gulp-size');
20 | var xo = require('gulp-xo');
21 |
22 | var reload = browserSync.reload;
23 |
24 | var generateShims = require('./gulp/generate-shims');
25 | var processShaders = require('./gulp/process-shaders');
26 |
27 | var runLint = function(src) {
28 | return gulp.src(src)
29 | .pipe(xo());
30 | };
31 |
32 | gulp.task('lint', function() {
33 | return runLint(['lib/**/*.js', 'gulp/**/*.js', 'gulpfile.js']);
34 | });
35 |
36 | gulp.task('shaders', function() {
37 | return gulp.src('lib/**/*.glsl')
38 | .pipe(processShaders())
39 | .pipe(gulp.dest('.tmp/shaders'));
40 | });
41 |
42 | gulp.task('create-main-js', function() {
43 | return gulp.src(['lib/**/*.js'])
44 | .pipe(gulpif('!main.js', generateShims()))
45 | .pipe(order([
46 | '!main.js',
47 | 'main.js'
48 | ]))
49 | .pipe(concat('main.js'))
50 | .pipe(gulp.dest('.tmp'));
51 | });
52 |
53 | function getCopyrightHeaders() {
54 | var copyrightHeader = fs.readFileSync('lib/copyright-header.js').toString();
55 | var shaderCopyrightHeader = fs.readFileSync('.tmp/shaders/shader-copyright-header.js').toString();
56 |
57 | return copyrightHeader + '\n' + shaderCopyrightHeader;
58 | }
59 |
60 | function optimize(options) {
61 | var source = path.join(options.baseUrl, options.include) + '.js';
62 | return gulp.src(source)
63 | .pipe(requirejsOptimize(options));
64 | }
65 |
66 | gulp.task('scripts', ['create-main-js', 'shaders'], function() {
67 | var copyright = getCopyrightHeaders();
68 |
69 | var requirejsOptions = {
70 | name: '../node_modules/almond/almond',
71 |
72 | wrap: {
73 | start: copyright + '(function() {',
74 | end: '})();'
75 | },
76 |
77 | useStrict: true,
78 |
79 | inlineText: true,
80 | stubModules: ['text'],
81 |
82 | skipModuleInsertion: true,
83 |
84 | baseUrl: 'lib',
85 |
86 | include: '../.tmp/main',
87 | paths: {
88 | text: '../node_modules/requirejs-text/text'
89 | }
90 | };
91 |
92 | var unminified = optimize(assign({}, requirejsOptions, {
93 | out: 'cesium-sensor-volumes.js',
94 | optimize: 'none'
95 | }));
96 |
97 | var minifiedOptions = assign({}, requirejsOptions, {
98 | out: 'cesium-sensor-volumes.min.js',
99 | optimize: 'uglify2'
100 | });
101 |
102 | // Use minified versions of shaders
103 | globby.sync(['lib/**/*.glsl']).forEach(function(shader) {
104 | shader = path.relative('lib', shader).replace(/\\/g, '/').replace(/\.glsl$/, '');
105 | minifiedOptions.paths[shader] = path.join('../.tmp/shaders', shader);
106 | });
107 |
108 | var minified = optimize(minifiedOptions);
109 |
110 | return es.merge(unminified, minified)
111 | .pipe(gulp.dest('dist'));
112 | });
113 |
114 | gulp.task('clean', del.bind(null, ['coverage', '.tmp', 'dist']));
115 |
116 | gulp.task('test-lint', function() {
117 | return runLint(['test/**/*.js']);
118 | });
119 |
120 | function test(done, options) {
121 | var Server = require('karma').Server;
122 |
123 | var server = new Server(assign({
124 | configFile: path.join(__dirname, '/test/karma.conf.js'),
125 | singleRun: true
126 | }, options), done);
127 |
128 | server.start();
129 | }
130 |
131 | gulp.task('test', ['test-lint'], function(done) {
132 | test(done);
133 | });
134 |
135 | gulp.task('test-ci', ['test-lint'], function(done) {
136 | test(done, {
137 | browsers: ['Electron'],
138 | client: {
139 | args: [true]
140 | }
141 | });
142 | });
143 |
144 | gulp.task('serve', function(done) {
145 | runSequence('build', 'run', 'watch', done);
146 | });
147 |
148 | gulp.task('run', function(done) {
149 | browserSync.init({
150 | server: '.'
151 | }, done);
152 | });
153 |
154 | gulp.task('watch', function() {
155 | gulp.watch(['examples/**/*.html', 'examples/**/*.czml'], reload);
156 | gulp.watch(['lib/**/*.glsl'], ['build-reload']);
157 | gulp.watch(['lib/**/*.js'], ['build-reload']);
158 | });
159 |
160 | gulp.task('build-reload', ['build'], reload);
161 |
162 | gulp.task('build', ['lint', 'scripts'], function() {
163 | return gulp.src('dist/**/*')
164 | .pipe(size({ title: 'build', gzip: true }));
165 | });
166 |
167 | gulp.task('ci', function(done) {
168 | runSequence('lint', 'test-ci', 'build', done);
169 | });
170 |
171 | gulp.task('default', function(done) {
172 | runSequence('clean', 'build', done);
173 | });
174 |
--------------------------------------------------------------------------------
/test/rectangular/rectangular-sensor-graphics-spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-nested-callbacks */
2 | define([
3 | 'rectangular/rectangular-sensor-graphics',
4 | 'Cesium/Core/Color',
5 | 'Cesium/DataSources/ColorMaterialProperty',
6 | 'Cesium/DataSources/ConstantProperty',
7 | '../matchers/add-to-throw-developer-error-matcher'
8 | ], function(
9 | RectangularSensorGraphics,
10 | Color,
11 | ColorMaterialProperty,
12 | ConstantProperty,
13 | addToThrowDeveloperErrorMatcher
14 | ) {
15 | 'use strict';
16 |
17 | /* global describe, it, beforeEach, expect */
18 |
19 | describe('rectangular sensor graphics', function() {
20 | describe('merge', function() {
21 | beforeEach(addToThrowDeveloperErrorMatcher);
22 |
23 | it('should assign unassigned properties', function() {
24 | var source = new RectangularSensorGraphics();
25 | source.lateralSurfaceMaterial = new ColorMaterialProperty();
26 | source.xHalfAngle = new ConstantProperty();
27 | source.yHalfAngle = new ConstantProperty();
28 | source.intersectionColor = new ConstantProperty();
29 | source.radius = new ConstantProperty();
30 | source.show = new ConstantProperty();
31 | source.showIntersection = new ConstantProperty();
32 | source.intersectionWidth = new ConstantProperty();
33 |
34 | var target = new RectangularSensorGraphics();
35 | target.merge(source);
36 |
37 | expect(target.lateralSurfaceMaterial).toBe(source.lateralSurfaceMaterial);
38 | expect(target.xHalfAngle).toBe(source.xHalfAngle);
39 | expect(target.yHalfAngle).toBe(source.yHalfAngle);
40 | expect(target.intersectionColor).toBe(source.intersectionColor);
41 | expect(target.radius).toBe(source.radius);
42 | expect(target.show).toBe(source.show);
43 | expect(target.showIntersection).toBe(source.showIntersection);
44 | expect(target.intersectionWidth).toBe(source.intersectionWidth);
45 | });
46 |
47 | it('should not assign assigned properties', function() {
48 | var source = new RectangularSensorGraphics();
49 | source.lateralSurfaceMaterial = new ColorMaterialProperty();
50 | source.xHalfAngle = new ConstantProperty();
51 | source.yHalfAngle = new ConstantProperty();
52 | source.intersectionColor = new ConstantProperty();
53 | source.radius = new ConstantProperty();
54 | source.show = new ConstantProperty();
55 | source.showIntersection = new ConstantProperty();
56 | source.intersectionWidth = new ConstantProperty();
57 |
58 | var lateralSurfaceMaterial = new ColorMaterialProperty();
59 | var xHalfAngle = new ConstantProperty();
60 | var yHalfAngle = new ConstantProperty();
61 | var intersectionColor = new ConstantProperty();
62 | var radius = new ConstantProperty();
63 | var show = new ConstantProperty();
64 | var showIntersection = new ConstantProperty();
65 | var intersectionWidth = new ConstantProperty();
66 |
67 | var target = new RectangularSensorGraphics();
68 | target.lateralSurfaceMaterial = lateralSurfaceMaterial;
69 | target.xHalfAngle = xHalfAngle;
70 | target.yHalfAngle = yHalfAngle;
71 | target.intersectionColor = intersectionColor;
72 | target.radius = radius;
73 | target.show = show;
74 | target.showIntersection = showIntersection;
75 | target.intersectionWidth = intersectionWidth;
76 |
77 | target.merge(source);
78 |
79 | expect(target.lateralSurfaceMaterial).toBe(lateralSurfaceMaterial);
80 | expect(target.xHalfAngle).toBe(xHalfAngle);
81 | expect(target.yHalfAngle).toBe(yHalfAngle);
82 | expect(target.intersectionColor).toBe(intersectionColor);
83 | expect(target.radius).toBe(radius);
84 | expect(target.show).toBe(show);
85 | expect(target.showIntersection).toBe(showIntersection);
86 | expect(target.intersectionWidth).toBe(intersectionWidth);
87 | });
88 |
89 | it('should throws if source undefined', function() {
90 | var target = new RectangularSensorGraphics();
91 | expect(function() {
92 | target.merge(undefined);
93 | }).toThrowDeveloperError();
94 | });
95 | });
96 |
97 | it('should clone', function() {
98 | var source = new RectangularSensorGraphics();
99 | source.lateralSurfaceMaterial = new ColorMaterialProperty();
100 | source.xHalfAngle = new ConstantProperty();
101 | source.yHalfAngle = new ConstantProperty();
102 | source.intersectionColor = new ConstantProperty();
103 | source.radius = new ConstantProperty();
104 | source.show = new ConstantProperty();
105 | source.showIntersection = new ConstantProperty();
106 | source.intersectionWidth = new ConstantProperty();
107 |
108 | var result = source.clone();
109 | expect(result.lateralSurfaceMaterial).toBe(source.lateralSurfaceMaterial);
110 | expect(result.xHalfAngle).toBe(source.xHalfAngle);
111 | expect(result.yHalfAngle).toBe(source.yHalfAngle);
112 | expect(result.intersectionColor).toBe(source.intersectionColor);
113 | expect(result.radius).toBe(source.radius);
114 | expect(result.show).toBe(source.show);
115 | expect(result.showIntersection).toBe(source.showIntersection);
116 | expect(result.intersectionWidth).toBe(source.intersectionWidth);
117 | });
118 | });
119 | });
120 |
--------------------------------------------------------------------------------
/lib/rectangular/rectangular-pyramid-sensor-volume.js:
--------------------------------------------------------------------------------
1 | define(function(require) {
2 | 'use strict';
3 |
4 | var clone = require('Cesium/Core/clone');
5 | var defaultValue = require('Cesium/Core/defaultValue');
6 | var defined = require('Cesium/Core/defined');
7 | var defineProperties = require('Cesium/Core/defineProperties');
8 | var destroyObject = require('Cesium/Core/destroyObject');
9 | var DeveloperError = require('Cesium/Core/DeveloperError');
10 | var CesiumMath = require('Cesium/Core/Math');
11 | var Spherical = require('Cesium/Core/Spherical');
12 |
13 | var CustomSensorVolume = require('../custom/custom-sensor-volume');
14 |
15 | function assignSpherical(index, array, clock, cone) {
16 | var spherical = array[index];
17 | if (!defined(spherical)) {
18 | spherical = new Spherical();
19 | array[index] = spherical;
20 | }
21 | spherical.clock = clock;
22 | spherical.cone = cone;
23 | spherical.magnitude = 1.0;
24 | }
25 |
26 | function updateDirections(rectangularSensor) {
27 | var directions = rectangularSensor._customSensor.directions;
28 |
29 | // At 90 degrees the sensor is completely open, and tan() goes to infinity.
30 | var tanX = Math.tan(Math.min(rectangularSensor._xHalfAngle, CesiumMath.toRadians(89.0)));
31 | var tanY = Math.tan(Math.min(rectangularSensor._yHalfAngle, CesiumMath.toRadians(89.0)));
32 | var theta = Math.atan(tanX / tanY);
33 | var cone = Math.atan(Math.sqrt((tanX * tanX) + (tanY * tanY)));
34 |
35 | assignSpherical(0, directions, theta, cone);
36 | assignSpherical(1, directions, CesiumMath.toRadians(180.0) - theta, cone);
37 | assignSpherical(2, directions, CesiumMath.toRadians(180.0) + theta, cone);
38 | assignSpherical(3, directions, -theta, cone);
39 |
40 | directions.length = 4;
41 | rectangularSensor._customSensor.directions = directions;
42 | }
43 |
44 | var RectangularPyramidSensorVolume = function(options) {
45 | options = defaultValue(options, defaultValue.EMPTY_OBJECT);
46 |
47 | var customSensorOptions = clone(options);
48 | customSensorOptions._pickPrimitive = defaultValue(options._pickPrimitive, this);
49 | customSensorOptions.directions = undefined;
50 | this._customSensor = new CustomSensorVolume(customSensorOptions);
51 |
52 | this._xHalfAngle = defaultValue(options.xHalfAngle, CesiumMath.PI_OVER_TWO);
53 | this._yHalfAngle = defaultValue(options.yHalfAngle, CesiumMath.PI_OVER_TWO);
54 |
55 | updateDirections(this);
56 | };
57 |
58 | defineProperties(RectangularPyramidSensorVolume.prototype, {
59 | xHalfAngle: {
60 | get: function() {
61 | return this._xHalfAngle;
62 | },
63 | set: function(value) {
64 | // >>includeStart('debug', pragmas.debug)
65 | if (value > CesiumMath.PI_OVER_TWO) {
66 | throw new DeveloperError('xHalfAngle must be less than or equal to 90 degrees.');
67 | }
68 | // >>includeEnd('debug');
69 |
70 | if (this._xHalfAngle !== value) {
71 | this._xHalfAngle = value;
72 | updateDirections(this);
73 | }
74 | }
75 | },
76 | yHalfAngle: {
77 | get: function() {
78 | return this._yHalfAngle;
79 | },
80 | set: function(value) {
81 | // >>includeStart('debug', pragmas.debug)
82 | if (value > CesiumMath.PI_OVER_TWO) {
83 | throw new DeveloperError('yHalfAngle must be less than or equal to 90 degrees.');
84 | }
85 | // >>includeEnd('debug');
86 |
87 | if (this._yHalfAngle !== value) {
88 | this._yHalfAngle = value;
89 | updateDirections(this);
90 | }
91 | }
92 | },
93 | show: {
94 | get: function() {
95 | return this._customSensor.show;
96 | },
97 | set: function(value) {
98 | this._customSensor.show = value;
99 | }
100 | },
101 | showIntersection: {
102 | get: function() {
103 | return this._customSensor.showIntersection;
104 | },
105 | set: function(value) {
106 | this._customSensor.showIntersection = value;
107 | }
108 | },
109 | showThroughEllipsoid: {
110 | get: function() {
111 | return this._customSensor.showThroughEllipsoid;
112 | },
113 | set: function(value) {
114 | this._customSensor.showThroughEllipsoid = value;
115 | }
116 | },
117 | modelMatrix: {
118 | get: function() {
119 | return this._customSensor.modelMatrix;
120 | },
121 | set: function(value) {
122 | this._customSensor.modelMatrix = value;
123 | }
124 | },
125 | radius: {
126 | get: function() {
127 | return this._customSensor.radius;
128 | },
129 | set: function(value) {
130 | this._customSensor.radius = value;
131 | }
132 | },
133 | lateralSurfaceMaterial: {
134 | get: function() {
135 | return this._customSensor.lateralSurfaceMaterial;
136 | },
137 | set: function(value) {
138 | this._customSensor.lateralSurfaceMaterial = value;
139 | }
140 | },
141 | intersectionColor: {
142 | get: function() {
143 | return this._customSensor.intersectionColor;
144 | },
145 | set: function(value) {
146 | this._customSensor.intersectionColor = value;
147 | }
148 | },
149 | intersectionWidth: {
150 | get: function() {
151 | return this._customSensor.intersectionWidth;
152 | },
153 | set: function(value) {
154 | this._customSensor.intersectionWidth = value;
155 | }
156 | },
157 | id: {
158 | get: function() {
159 | return this._customSensor.id;
160 | },
161 | set: function(value) {
162 | this._customSensor.id = value;
163 | }
164 | }
165 | });
166 |
167 | RectangularPyramidSensorVolume.prototype.update = function(frameState) {
168 | this._customSensor.update(frameState);
169 | };
170 |
171 | RectangularPyramidSensorVolume.prototype.isDestroyed = function() {
172 | return false;
173 | };
174 |
175 | RectangularPyramidSensorVolume.prototype.destroy = function() {
176 | this._customSensor = this._customSensor && this._customSensor.destroy();
177 | return destroyObject(this);
178 | };
179 |
180 | return RectangularPyramidSensorVolume;
181 | });
182 |
--------------------------------------------------------------------------------
/lib/custom/custom-pattern-sensor-graphics.js:
--------------------------------------------------------------------------------
1 | define(function(require) {
2 | 'use strict';
3 |
4 | var defaultValue = require('Cesium/Core/defaultValue');
5 | var defined = require('Cesium/Core/defined');
6 | var defineProperties = require('Cesium/Core/defineProperties');
7 | var DeveloperError = require('Cesium/Core/DeveloperError');
8 | var Event = require('Cesium/Core/Event');
9 |
10 | var createMaterialPropertyDescriptor = require('Cesium/DataSources/createMaterialPropertyDescriptor');
11 | var createPropertyDescriptor = require('Cesium/DataSources/createPropertyDescriptor');
12 |
13 | /**
14 | * An optionally time-dynamic custom patterned sensor.
15 | *
16 | * @alias CustomPatternSensorGraphics
17 | * @constructor
18 | */
19 | var CustomPatternSensorGraphics = function(options) {
20 | this._directions = undefined;
21 | this._directionsSubscription = undefined;
22 |
23 | this._lateralSurfaceMaterial = undefined;
24 | this._lateralSurfaceMaterialSubscription = undefined;
25 |
26 | this._intersectionColor = undefined;
27 | this._intersectionColorSubscription = undefined;
28 | this._intersectionWidth = undefined;
29 | this._intersectionWidthSubscription = undefined;
30 | this._showIntersection = undefined;
31 | this._showIntersectionSubscription = undefined;
32 | this._radius = undefined;
33 | this._radiusSubscription = undefined;
34 | this._show = undefined;
35 | this._showSubscription = undefined;
36 | this._definitionChanged = new Event();
37 |
38 | this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
39 | };
40 |
41 | defineProperties(CustomPatternSensorGraphics.prototype, {
42 | /**
43 | * Gets the event that is raised whenever a new property is assigned.
44 | * @memberof CustomPatternSensorGraphics.prototype
45 | *
46 | * @type {Event}
47 | * @readonly
48 | */
49 | definitionChanged: {
50 | get: function() {
51 | return this._definitionChanged;
52 | }
53 | },
54 |
55 | /**
56 | * A {@link Property} which returns an array of {@link Spherical} instances representing the sensor's projection.
57 | * @memberof CustomPatternSensorGraphics.prototype
58 | * @type {Property}
59 | */
60 | directions: createPropertyDescriptor('directions'),
61 |
62 | /**
63 | * Gets or sets the {@link MaterialProperty} specifying the the sensor's appearance.
64 | * @memberof CustomPatternSensorGraphics.prototype
65 | * @type {MaterialProperty}
66 | */
67 | lateralSurfaceMaterial: createMaterialPropertyDescriptor('lateralSurfaceMaterial'),
68 |
69 | /**
70 | * Gets or sets the {@link Color} {@link Property} specifying the color of the line formed by the intersection of the sensor and other central bodies.
71 | * @memberof CustomPatternSensorGraphics.prototype
72 | * @type {Property}
73 | */
74 | intersectionColor: createPropertyDescriptor('intersectionColor'),
75 |
76 | /**
77 | * Gets or sets the numeric {@link Property} specifying the width of the line formed by the intersection of the sensor and other central bodies.
78 | * @memberof CustomPatternSensorGraphics.prototype
79 | * @type {Property}
80 | */
81 | intersectionWidth: createPropertyDescriptor('intersectionWidth'),
82 |
83 | /**
84 | * Gets or sets the boolean {@link Property} specifying the visibility of the line formed by the intersection of the sensor and other central bodies.
85 | * @memberof CustomPatternSensorGraphics.prototype
86 | * @type {Property}
87 | */
88 | showIntersection: createPropertyDescriptor('showIntersection'),
89 |
90 | /**
91 | * Gets or sets the numeric {@link Property} specifying the radius of the sensor's projection.
92 | * @memberof CustomPatternSensorGraphics.prototype
93 | * @type {Property}
94 | */
95 | radius: createPropertyDescriptor('radius'),
96 |
97 | /**
98 | * Gets or sets the boolean {@link Property} specifying the visibility of the sensor.
99 | * @memberof CustomPatternSensorGraphics.prototype
100 | * @type {Property}
101 | */
102 | show: createPropertyDescriptor('show')
103 | });
104 |
105 | /**
106 | * Duplicates a CustomPatternSensorGraphics instance.
107 | *
108 | * @param {CustomPatternSensorGraphics} [result] The object onto which to store the result.
109 | * @returns {CustomPatternSensorGraphics} The modified result parameter or a new instance if one was not provided.
110 | */
111 | CustomPatternSensorGraphics.prototype.clone = function(result) {
112 | if (!defined(result)) {
113 | result = new CustomPatternSensorGraphics();
114 | }
115 | result.directions = this.directions;
116 | result.radius = this.radius;
117 | result.show = this.show;
118 | result.showIntersection = this.showIntersection;
119 | result.intersectionColor = this.intersectionColor;
120 | result.intersectionWidth = this.intersectionWidth;
121 | result.lateralSurfaceMaterial = this.lateralSurfaceMaterial;
122 | return result;
123 | };
124 |
125 | /**
126 | * Assigns each unassigned property on this object to the value
127 | * of the same property on the provided source object.
128 | *
129 | * @param {CustomPatternSensorGraphics} source The object to be merged into this object.
130 | */
131 | CustomPatternSensorGraphics.prototype.merge = function(source) {
132 | // >>includeStart('debug', pragmas.debug);
133 | if (!defined(source)) {
134 | throw new DeveloperError('source is required.');
135 | }
136 | // >>includeEnd('debug');
137 |
138 | this.directions = defaultValue(this.directions, source.directions);
139 | this.radius = defaultValue(this.radius, source.radius);
140 | this.show = defaultValue(this.show, source.show);
141 | this.showIntersection = defaultValue(this.showIntersection, source.showIntersection);
142 | this.intersectionColor = defaultValue(this.intersectionColor, source.intersectionColor);
143 | this.intersectionWidth = defaultValue(this.intersectionWidth, source.intersectionWidth);
144 | this.lateralSurfaceMaterial = defaultValue(this.lateralSurfaceMaterial, source.lateralSurfaceMaterial);
145 | };
146 |
147 | return CustomPatternSensorGraphics;
148 | });
149 |
--------------------------------------------------------------------------------
/test/conic/conic-sensor-graphics-spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-nested-callbacks */
2 | define([
3 | 'conic/conic-sensor-graphics',
4 | 'Cesium/Core/Color',
5 | 'Cesium/DataSources/ColorMaterialProperty',
6 | 'Cesium/DataSources/ConstantProperty',
7 | '../matchers/add-to-throw-developer-error-matcher'
8 | ], function(
9 | ConicSensorGraphics,
10 | Color,
11 | ColorMaterialProperty,
12 | ConstantProperty,
13 | addToThrowDeveloperErrorMatcher
14 | ) {
15 | 'use strict';
16 |
17 | /* global describe, it, beforeEach, expect */
18 |
19 | describe('conic sensor graphics', function() {
20 | describe('merge', function() {
21 | beforeEach(addToThrowDeveloperErrorMatcher);
22 |
23 | it('should assign unassigned properties', function() {
24 | var source = new ConicSensorGraphics();
25 | source.lateralSurfaceMaterial = new ColorMaterialProperty();
26 | source.innerHalfAngle = new ConstantProperty(1);
27 | source.maximumClockAngle = new ConstantProperty(1);
28 | source.minimumClockAngle = new ConstantProperty(1);
29 | source.outerHalfAngle = new ConstantProperty(1);
30 | source.intersectionColor = new ConstantProperty(Color.WHITE);
31 | source.radius = new ConstantProperty(1);
32 | source.show = new ConstantProperty(true);
33 | source.showIntersection = new ConstantProperty(true);
34 | source.intersectionWidth = new ConstantProperty(1);
35 |
36 | var target = new ConicSensorGraphics();
37 | target.merge(source);
38 |
39 | expect(target.lateralSurfaceMaterial).toBe(source.lateralSurfaceMaterial);
40 | expect(target.innerHalfAngle).toBe(source.innerHalfAngle);
41 | expect(target.maximumClockAngle).toBe(source.maximumClockAngle);
42 | expect(target.minimumClockAngle).toBe(source.minimumClockAngle);
43 | expect(target.outerHalfAngle).toBe(source.outerHalfAngle);
44 | expect(target.intersectionColor).toBe(source.intersectionColor);
45 | expect(target.radius).toBe(source.radius);
46 | expect(target.show).toBe(source.show);
47 | expect(target.showIntersection).toBe(source.showIntersection);
48 | expect(target.intersectionWidth).toBe(source.intersectionWidth);
49 | });
50 |
51 | it('should not assign assigned properties', function() {
52 | var source = new ConicSensorGraphics();
53 | source.lateralSurfaceMaterial = new ColorMaterialProperty();
54 | source.innerHalfAngle = new ConstantProperty(1);
55 | source.maximumClockAngle = new ConstantProperty(1);
56 | source.minimumClockAngle = new ConstantProperty(1);
57 | source.outerHalfAngle = new ConstantProperty(1);
58 | source.intersectionColor = new ConstantProperty(Color.WHITE);
59 | source.radius = new ConstantProperty(1);
60 | source.show = new ConstantProperty(true);
61 | source.showIntersection = new ConstantProperty(true);
62 | source.intersectionWidth = new ConstantProperty(1);
63 |
64 | var lateralSurfaceMaterial = new ColorMaterialProperty();
65 | var innerHalfAngle = new ConstantProperty(1);
66 | var maximumClockAngle = new ConstantProperty(1);
67 | var minimumClockAngle = new ConstantProperty(1);
68 | var outerHalfAngle = new ConstantProperty(1);
69 | var intersectionColor = new ConstantProperty(Color.WHITE);
70 | var radius = new ConstantProperty(1);
71 | var show = new ConstantProperty(true);
72 | var showIntersection = new ConstantProperty(true);
73 | var intersectionWidth = new ConstantProperty(1);
74 |
75 | var target = new ConicSensorGraphics();
76 | target.lateralSurfaceMaterial = lateralSurfaceMaterial;
77 | target.innerHalfAngle = innerHalfAngle;
78 | target.maximumClockAngle = maximumClockAngle;
79 | target.minimumClockAngle = minimumClockAngle;
80 | target.outerHalfAngle = outerHalfAngle;
81 | target.intersectionColor = intersectionColor;
82 | target.radius = radius;
83 | target.show = show;
84 | target.showIntersection = showIntersection;
85 | target.intersectionWidth = intersectionWidth;
86 |
87 | target.merge(source);
88 |
89 | expect(target.lateralSurfaceMaterial).toBe(lateralSurfaceMaterial);
90 | expect(target.innerHalfAngle).toBe(innerHalfAngle);
91 | expect(target.maximumClockAngle).toBe(maximumClockAngle);
92 | expect(target.minimumClockAngle).toBe(minimumClockAngle);
93 | expect(target.outerHalfAngle).toBe(outerHalfAngle);
94 | expect(target.intersectionColor).toBe(intersectionColor);
95 | expect(target.radius).toBe(radius);
96 | expect(target.show).toBe(show);
97 | expect(target.showIntersection).toBe(showIntersection);
98 | expect(target.intersectionWidth).toBe(intersectionWidth);
99 | });
100 |
101 | it('should throw if source undefined', function() {
102 | var target = new ConicSensorGraphics();
103 | expect(function() {
104 | target.merge(undefined);
105 | }).toThrowDeveloperError();
106 | });
107 | });
108 |
109 | it('should clone', function() {
110 | var source = new ConicSensorGraphics();
111 | source.lateralSurfaceMaterial = new ColorMaterialProperty();
112 | source.innerHalfAngle = new ConstantProperty(1);
113 | source.maximumClockAngle = new ConstantProperty(1);
114 | source.minimumClockAngle = new ConstantProperty(1);
115 | source.outerHalfAngle = new ConstantProperty(1);
116 | source.intersectionColor = new ConstantProperty(Color.WHITE);
117 | source.radius = new ConstantProperty(1);
118 | source.show = new ConstantProperty(true);
119 | source.showIntersection = new ConstantProperty(true);
120 | source.intersectionWidth = new ConstantProperty(1);
121 |
122 | var result = source.clone();
123 | expect(result.lateralSurfaceMaterial).toBe(source.lateralSurfaceMaterial);
124 | expect(result.innerHalfAngle).toBe(source.innerHalfAngle);
125 | expect(result.maximumClockAngle).toBe(source.maximumClockAngle);
126 | expect(result.minimumClockAngle).toBe(source.minimumClockAngle);
127 | expect(result.outerHalfAngle).toBe(source.outerHalfAngle);
128 | expect(result.intersectionColor).toBe(source.intersectionColor);
129 | expect(result.radius).toBe(source.radius);
130 | expect(result.show).toBe(source.show);
131 | expect(result.showIntersection).toBe(source.showIntersection);
132 | expect(result.intersectionWidth).toBe(source.intersectionWidth);
133 | });
134 | });
135 | });
136 |
--------------------------------------------------------------------------------
/lib/rectangular/rectangular-sensor-graphics.js:
--------------------------------------------------------------------------------
1 | define(function(require) {
2 | 'use strict';
3 |
4 | var defaultValue = require('Cesium/Core/defaultValue');
5 | var defined = require('Cesium/Core/defined');
6 | var defineProperties = require('Cesium/Core/defineProperties');
7 | var DeveloperError = require('Cesium/Core/DeveloperError');
8 | var Event = require('Cesium/Core/Event');
9 |
10 | var createPropertyDescriptor = require('Cesium/DataSources/createPropertyDescriptor');
11 |
12 | /**
13 | * An optionally time-dynamic pyramid.
14 | *
15 | * @alias RectangularSensorGraphics
16 | * @constructor
17 | */
18 | var RectangularSensorGraphics = function() {
19 | this._xHalfAngle = undefined;
20 | this._xHalfAngleSubscription = undefined;
21 | this._yHalfAngle = undefined;
22 | this._yHalfAngleSubscription = undefined;
23 |
24 | this._lateralSurfaceMaterial = undefined;
25 | this._lateralSurfaceMaterialSubscription = undefined;
26 |
27 | this._intersectionColor = undefined;
28 | this._intersectionColorSubscription = undefined;
29 | this._intersectionWidth = undefined;
30 | this._intersectionWidthSubscription = undefined;
31 | this._showIntersection = undefined;
32 | this._showIntersectionSubscription = undefined;
33 | this._radius = undefined;
34 | this._radiusSubscription = undefined;
35 | this._show = undefined;
36 | this._showSubscription = undefined;
37 | this._definitionChanged = new Event();
38 | };
39 |
40 | defineProperties(RectangularSensorGraphics.prototype, {
41 | /**
42 | * Gets the event that is raised whenever a new property is assigned.
43 | * @memberof RectangularSensorGraphics.prototype
44 | *
45 | * @type {Event}
46 | * @readonly
47 | */
48 | definitionChanged: {
49 | get: function() {
50 | return this._definitionChanged;
51 | }
52 | },
53 |
54 | /**
55 | * A {@link Property} which returns an array of {@link Spherical} instances representing the pyramid's projection.
56 | * @memberof RectangularSensorGraphics.prototype
57 | * @type {Property}
58 | */
59 | xHalfAngle: createPropertyDescriptor('xHalfAngle'),
60 |
61 | /**
62 | * A {@link Property} which returns an array of {@link Spherical} instances representing the pyramid's projection.
63 | * @memberof RectangularSensorGraphics.prototype
64 | * @type {Property}
65 | */
66 | yHalfAngle: createPropertyDescriptor('yHalfAngle'),
67 |
68 | /**
69 | * Gets or sets the {@link MaterialProperty} specifying the the pyramid's appearance.
70 | * @memberof RectangularSensorGraphics.prototype
71 | * @type {MaterialProperty}
72 | */
73 | lateralSurfaceMaterial: createPropertyDescriptor('lateralSurfaceMaterial'),
74 |
75 | /**
76 | * Gets or sets the {@link Color} {@link Property} specifying the color of the line formed by the intersection of the pyramid and other central bodies.
77 | * @memberof RectangularSensorGraphics.prototype
78 | * @type {Property}
79 | */
80 | intersectionColor: createPropertyDescriptor('intersectionColor'),
81 |
82 | /**
83 | * Gets or sets the numeric {@link Property} specifying the width of the line formed by the intersection of the pyramid and other central bodies.
84 | * @memberof RectangularSensorGraphics.prototype
85 | * @type {Property}
86 | */
87 | intersectionWidth: createPropertyDescriptor('intersectionWidth'),
88 |
89 | /**
90 | * Gets or sets the boolean {@link Property} specifying the visibility of the line formed by the intersection of the pyramid and other central bodies.
91 | * @memberof RectangularSensorGraphics.prototype
92 | * @type {Property}
93 | */
94 | showIntersection: createPropertyDescriptor('showIntersection'),
95 |
96 | /**
97 | * Gets or sets the numeric {@link Property} specifying the radius of the pyramid's projection.
98 | * @memberof RectangularSensorGraphics.prototype
99 | * @type {Property}
100 | */
101 | radius: createPropertyDescriptor('radius'),
102 |
103 | /**
104 | * Gets or sets the boolean {@link Property} specifying the visibility of the pyramid.
105 | * @memberof RectangularSensorGraphics.prototype
106 | * @type {Property}
107 | */
108 | show: createPropertyDescriptor('show')
109 | });
110 |
111 | /**
112 | * Duplicates a RectangularSensorGraphics instance.
113 | *
114 | * @param {RectangularSensorGraphics} [result] The object onto which to store the result.
115 | * @returns {RectangularSensorGraphics} The modified result parameter or a new instance if one was not provided.
116 | */
117 | RectangularSensorGraphics.prototype.clone = function(result) {
118 | if (!defined(result)) {
119 | result = new RectangularSensorGraphics();
120 | }
121 | result.xHalfAngle = this.xHalfAngle;
122 | result.yHalfAngle = this.yHalfAngle;
123 | result.radius = this.radius;
124 | result.show = this.show;
125 | result.showIntersection = this.showIntersection;
126 | result.intersectionColor = this.intersectionColor;
127 | result.intersectionWidth = this.intersectionWidth;
128 | result.lateralSurfaceMaterial = this.lateralSurfaceMaterial;
129 | return result;
130 | };
131 |
132 | /**
133 | * Assigns each unassigned property on this object to the value
134 | * of the same property on the provided source object.
135 | *
136 | * @param {RectangularSensorGraphics} source The object to be merged into this object.
137 | */
138 | RectangularSensorGraphics.prototype.merge = function(source) {
139 | // >>includeStart('debug', pragmas.debug);
140 | if (!defined(source)) {
141 | throw new DeveloperError('source is required.');
142 | }
143 | // >>includeEnd('debug');
144 |
145 | this.xHalfAngle = defaultValue(this.xHalfAngle, source.xHalfAngle);
146 | this.yHalfAngle = defaultValue(this.yHalfAngle, source.yHalfAngle);
147 | this.radius = defaultValue(this.radius, source.radius);
148 | this.show = defaultValue(this.show, source.show);
149 | this.showIntersection = defaultValue(this.showIntersection, source.showIntersection);
150 | this.intersectionColor = defaultValue(this.intersectionColor, source.intersectionColor);
151 | this.intersectionWidth = defaultValue(this.intersectionWidth, source.intersectionWidth);
152 | this.lateralSurfaceMaterial = defaultValue(this.lateralSurfaceMaterial, source.lateralSurfaceMaterial);
153 | };
154 |
155 | return RectangularSensorGraphics;
156 | });
157 |
--------------------------------------------------------------------------------
/lib/custom/custom-pattern-sensor-visualizer.js:
--------------------------------------------------------------------------------
1 | define(function(require) {
2 | 'use strict';
3 |
4 | var AssociativeArray = require('Cesium/Core/AssociativeArray');
5 | var Cartesian3 = require('Cesium/Core/Cartesian3');
6 | var Color = require('Cesium/Core/Color');
7 | var defined = require('Cesium/Core/defined');
8 | var destroyObject = require('Cesium/Core/destroyObject');
9 | var DeveloperError = require('Cesium/Core/DeveloperError');
10 | var Matrix3 = require('Cesium/Core/Matrix3');
11 | var Matrix4 = require('Cesium/Core/Matrix4');
12 | var Quaternion = require('Cesium/Core/Quaternion');
13 | var MaterialProperty = require('Cesium/DataSources/MaterialProperty');
14 | var Property = require('Cesium/DataSources/Property');
15 |
16 | var CustomSensorVolume = require('../custom/custom-sensor-volume');
17 | var removePrimitive = require('../util/remove-primitive');
18 |
19 | var defaultIntersectionColor = Color.WHITE;
20 | var defaultIntersectionWidth = 1.0;
21 | var defaultRadius = Number.POSITIVE_INFINITY;
22 |
23 | var matrix3Scratch = new Matrix3();
24 | var cachedPosition = new Cartesian3();
25 | var cachedOrientation = new Quaternion();
26 |
27 | /**
28 | * A {@link Visualizer} which maps {@link Entity#customPatternSensor} to a {@link CustomPatternSensor}.
29 | * @alias CustomPatternSensorVisualizer
30 | * @constructor
31 | *
32 | * @param {Scene} scene The scene the primitives will be rendered in.
33 | * @param {EntityCollection} entityCollection The entityCollection to visualize.
34 | */
35 | var CustomPatternSensorVisualizer = function(scene, entityCollection) {
36 | // >>includeStart('debug', pragmas.debug);
37 | if (!defined(scene)) {
38 | throw new DeveloperError('scene is required.');
39 | }
40 | if (!defined(entityCollection)) {
41 | throw new DeveloperError('entityCollection is required.');
42 | }
43 | // >>includeEnd('debug');
44 |
45 | entityCollection.collectionChanged.addEventListener(CustomPatternSensorVisualizer.prototype._onCollectionChanged, this);
46 |
47 | this._scene = scene;
48 | this._primitives = scene.primitives;
49 | this._entityCollection = entityCollection;
50 | this._hash = {};
51 | this._entitiesToVisualize = new AssociativeArray();
52 |
53 | this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
54 | };
55 |
56 | /**
57 | * Updates the primitives created by this visualizer to match their
58 | * Entity counterpart at the given time.
59 | *
60 | * @param {JulianDate} time The time to update to.
61 | * @returns {Boolean} This function always returns true.
62 | */
63 | CustomPatternSensorVisualizer.prototype.update = function(time) {
64 | // >>includeStart('debug', pragmas.debug);
65 | if (!defined(time)) {
66 | throw new DeveloperError('time is required.');
67 | }
68 | // >>includeEnd('debug');
69 |
70 | var entities = this._entitiesToVisualize.values;
71 | var hash = this._hash;
72 | var primitives = this._primitives;
73 |
74 | for (var i = 0, len = entities.length; i < len; i++) {
75 | var entity = entities[i];
76 | var customPatternSensorGraphics = entity._customPatternSensor;
77 |
78 | var position;
79 | var orientation;
80 | var directions;
81 | var data = hash[entity.id];
82 | var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(customPatternSensorGraphics._show, time, true);
83 |
84 | if (show) {
85 | position = Property.getValueOrUndefined(entity._position, time, cachedPosition);
86 | orientation = Property.getValueOrUndefined(entity._orientation, time, cachedOrientation);
87 | directions = Property.getValueOrUndefined(customPatternSensorGraphics._directions, time);
88 | show = defined(position) && defined(orientation) && defined(directions);
89 | }
90 |
91 | if (!show) {
92 | // don't bother creating or updating anything else
93 | if (defined(data)) {
94 | data.primitive.show = false;
95 | }
96 | continue;
97 | }
98 |
99 | var primitive = defined(data) ? data.primitive : undefined;
100 | if (!defined(primitive)) {
101 | primitive = new CustomSensorVolume();
102 | primitive.id = entity;
103 | primitives.add(primitive);
104 |
105 | data = {
106 | primitive: primitive,
107 | position: undefined,
108 | orientation: undefined
109 | };
110 | hash[entity.id] = data;
111 | }
112 |
113 | if (!Cartesian3.equals(position, data.position) || !Quaternion.equals(orientation, data.orientation)) {
114 | Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, matrix3Scratch), position, primitive.modelMatrix);
115 | data.position = Cartesian3.clone(position, data.position);
116 | data.orientation = Quaternion.clone(orientation, data.orientation);
117 | }
118 |
119 | primitive.show = true;
120 | primitive.directions = directions;
121 | primitive.radius = Property.getValueOrDefault(customPatternSensorGraphics._radius, time, defaultRadius);
122 | primitive.lateralSurfaceMaterial = MaterialProperty.getValue(time, customPatternSensorGraphics._lateralSurfaceMaterial, primitive.lateralSurfaceMaterial);
123 | primitive.intersectionColor = Property.getValueOrClonedDefault(customPatternSensorGraphics._intersectionColor, time, defaultIntersectionColor, primitive.intersectionColor);
124 | primitive.intersectionWidth = Property.getValueOrDefault(customPatternSensorGraphics._intersectionWidth, time, defaultIntersectionWidth);
125 | }
126 | return true;
127 | };
128 |
129 | /**
130 | * Returns true if this object was destroyed; otherwise, false.
131 | *
132 | * @returns {Boolean} True if this object was destroyed; otherwise, false.
133 | */
134 | CustomPatternSensorVisualizer.prototype.isDestroyed = function() {
135 | return false;
136 | };
137 |
138 | /**
139 | * Removes and destroys all primitives created by this instance.
140 | */
141 | CustomPatternSensorVisualizer.prototype.destroy = function() {
142 | var entities = this._entitiesToVisualize.values;
143 | var hash = this._hash;
144 | var primitives = this._primitives;
145 | for (var i = entities.length - 1; i > -1; i--) {
146 | removePrimitive(entities[i], hash, primitives);
147 | }
148 | return destroyObject(this);
149 | };
150 |
151 | /**
152 | * @private
153 | */
154 | CustomPatternSensorVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
155 | var i;
156 | var entity;
157 | var entities = this._entitiesToVisualize;
158 | var hash = this._hash;
159 | var primitives = this._primitives;
160 |
161 | for (i = added.length - 1; i > -1; i--) {
162 | entity = added[i];
163 | if (defined(entity._customPatternSensor) && defined(entity._position) && defined(entity._orientation)) {
164 | entities.set(entity.id, entity);
165 | }
166 | }
167 |
168 | for (i = changed.length - 1; i > -1; i--) {
169 | entity = changed[i];
170 | if (defined(entity._customPatternSensor) && defined(entity._position) && defined(entity._orientation)) {
171 | entities.set(entity.id, entity);
172 | } else {
173 | removePrimitive(entity, hash, primitives);
174 | entities.remove(entity.id);
175 | }
176 | }
177 |
178 | for (i = removed.length - 1; i > -1; i--) {
179 | entity = removed[i];
180 | removePrimitive(entity, hash, primitives);
181 | entities.remove(entity.id);
182 | }
183 | };
184 |
185 | return CustomPatternSensorVisualizer;
186 | });
187 |
--------------------------------------------------------------------------------
/lib/conic/conic-sensor-graphics.js:
--------------------------------------------------------------------------------
1 | define(function(require) {
2 | 'use strict';
3 |
4 | var defaultValue = require('Cesium/Core/defaultValue');
5 | var defined = require('Cesium/Core/defined');
6 | var defineProperties = require('Cesium/Core/defineProperties');
7 | var DeveloperError = require('Cesium/Core/DeveloperError');
8 | var Event = require('Cesium/Core/Event');
9 |
10 | var createMaterialPropertyDescriptor = require('Cesium/DataSources/createMaterialPropertyDescriptor');
11 | var createPropertyDescriptor = require('Cesium/DataSources/createPropertyDescriptor');
12 |
13 | /**
14 | * An optionally time-dynamic cone.
15 | *
16 | * @alias ConicSensorGraphics
17 | * @constructor
18 | */
19 | var ConicSensorGraphics = function(options) {
20 | this._minimumClockAngle = undefined;
21 | this._minimumClockAngleSubscription = undefined;
22 | this._maximumClockAngle = undefined;
23 | this._maximumClockAngleSubscription = undefined;
24 | this._innerHalfAngle = undefined;
25 | this._innerHalfAngleSubscription = undefined;
26 | this._outerHalfAngle = undefined;
27 | this._outerHalfAngleSubscription = undefined;
28 | this._lateralSurfaceMaterial = undefined;
29 | this._lateralSurfaceMaterialSubscription = undefined;
30 | this._intersectionColor = undefined;
31 | this._intersectionColorSubscription = undefined;
32 | this._intersectionWidth = undefined;
33 | this._intersectionWidthSubscription = undefined;
34 | this._showIntersection = undefined;
35 | this._showIntersectionSubscription = undefined;
36 | this._radius = undefined;
37 | this._radiusSubscription = undefined;
38 | this._show = undefined;
39 | this._showSubscription = undefined;
40 | this._definitionChanged = new Event();
41 |
42 | this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
43 | };
44 |
45 | defineProperties(ConicSensorGraphics.prototype, {
46 | /**
47 | * Gets the event that is raised whenever a new property is assigned.
48 | * @memberof ConicSensorGraphics.prototype
49 | *
50 | * @type {Event}
51 | * @readonly
52 | */
53 | definitionChanged: {
54 | get: function() {
55 | return this._definitionChanged;
56 | }
57 | },
58 |
59 | /**
60 | * Gets or sets the numeric {@link Property} specifying the the cone's minimum clock angle.
61 | * @memberof ConicSensorGraphics.prototype
62 | * @type {Property}
63 | */
64 | minimumClockAngle: createPropertyDescriptor('minimumClockAngle'),
65 |
66 | /**
67 | * Gets or sets the numeric {@link Property} specifying the the cone's maximum clock angle.
68 | * @memberof ConicSensorGraphics.prototype
69 | * @type {Property}
70 | */
71 | maximumClockAngle: createPropertyDescriptor('maximumClockAngle'),
72 |
73 | /**
74 | * Gets or sets the numeric {@link Property} specifying the the cone's inner half-angle.
75 | * @memberof ConicSensorGraphics.prototype
76 | * @type {Property}
77 | */
78 | innerHalfAngle: createPropertyDescriptor('innerHalfAngle'),
79 |
80 | /**
81 | * Gets or sets the numeric {@link Property} specifying the the cone's outer half-angle.
82 | * @memberof ConicSensorGraphics.prototype
83 | * @type {Property}
84 | */
85 | outerHalfAngle: createPropertyDescriptor('outerHalfAngle'),
86 |
87 | /**
88 | * Gets or sets the {@link MaterialProperty} specifying the the cone's appearance.
89 | * @memberof ConicSensorGraphics.prototype
90 | * @type {MaterialProperty}
91 | */
92 | lateralSurfaceMaterial: createMaterialPropertyDescriptor('lateralSurfaceMaterial'),
93 |
94 | /**
95 | * Gets or sets the {@link Color} {@link Property} specifying the color of the line formed by the intersection of the cone and other central bodies.
96 | * @memberof ConicSensorGraphics.prototype
97 | * @type {Property}
98 | */
99 | intersectionColor: createPropertyDescriptor('intersectionColor'),
100 |
101 | /**
102 | * Gets or sets the numeric {@link Property} specifying the width of the line formed by the intersection of the cone and other central bodies.
103 | * @memberof ConicSensorGraphics.prototype
104 | * @type {Property}
105 | */
106 | intersectionWidth: createPropertyDescriptor('intersectionWidth'),
107 |
108 | /**
109 | * Gets or sets the boolean {@link Property} specifying the visibility of the line formed by the intersection of the cone and other central bodies.
110 | * @memberof ConicSensorGraphics.prototype
111 | * @type {Property}
112 | */
113 | showIntersection: createPropertyDescriptor('showIntersection'),
114 |
115 | /**
116 | * Gets or sets the numeric {@link Property} specifying the radius of the cone's projection.
117 | * @memberof ConicSensorGraphics.prototype
118 | * @type {Property}
119 | */
120 | radius: createPropertyDescriptor('radius'),
121 |
122 | /**
123 | * Gets or sets the boolean {@link Property} specifying the visibility of the cone.
124 | * @memberof ConicSensorGraphics.prototype
125 | * @type {Property}
126 | */
127 | show: createPropertyDescriptor('show')
128 | });
129 |
130 | /**
131 | * Duplicates a ConicSensorGraphics instance.
132 | *
133 | * @param {ConicSensorGraphics} [result] The object onto which to store the result.
134 | * @returns {ConicSensorGraphics} The modified result parameter or a new instance if one was not provided.
135 | */
136 | ConicSensorGraphics.prototype.clone = function(result) {
137 | if (!defined(result)) {
138 | result = new ConicSensorGraphics();
139 | }
140 | result.show = this.show;
141 | result.innerHalfAngle = this.innerHalfAngle;
142 | result.outerHalfAngle = this.outerHalfAngle;
143 | result.minimumClockAngle = this.minimumClockAngle;
144 | result.maximumClockAngle = this.maximumClockAngle;
145 | result.radius = this.radius;
146 | result.showIntersection = this.showIntersection;
147 | result.intersectionColor = this.intersectionColor;
148 | result.intersectionWidth = this.intersectionWidth;
149 | result.lateralSurfaceMaterial = this.lateralSurfaceMaterial;
150 | return result;
151 | };
152 |
153 | /**
154 | * Assigns each unassigned property on this object to the value
155 | * of the same property on the provided source object.
156 | *
157 | * @param {ConicSensorGraphics} source The object to be merged into this object.
158 | */
159 | ConicSensorGraphics.prototype.merge = function(source) {
160 | // >>includeStart('debug', pragmas.debug);
161 | if (!defined(source)) {
162 | throw new DeveloperError('source is required.');
163 | }
164 | // >>includeEnd('debug');
165 |
166 | this.show = defaultValue(this.show, source.show);
167 | this.innerHalfAngle = defaultValue(this.innerHalfAngle, source.innerHalfAngle);
168 | this.outerHalfAngle = defaultValue(this.outerHalfAngle, source.outerHalfAngle);
169 | this.minimumClockAngle = defaultValue(this.minimumClockAngle, source.minimumClockAngle);
170 | this.maximumClockAngle = defaultValue(this.maximumClockAngle, source.maximumClockAngle);
171 | this.radius = defaultValue(this.radius, source.radius);
172 | this.showIntersection = defaultValue(this.showIntersection, source.showIntersection);
173 | this.intersectionColor = defaultValue(this.intersectionColor, source.intersectionColor);
174 | this.intersectionWidth = defaultValue(this.intersectionWidth, source.intersectionWidth);
175 | this.lateralSurfaceMaterial = defaultValue(this.lateralSurfaceMaterial, source.lateralSurfaceMaterial);
176 | };
177 |
178 | return ConicSensorGraphics;
179 | });
180 |
--------------------------------------------------------------------------------
/lib/rectangular/rectangular-sensor-visualizer.js:
--------------------------------------------------------------------------------
1 | define(function(require) {
2 | 'use strict';
3 |
4 | var AssociativeArray = require('Cesium/Core/AssociativeArray');
5 | var Cartesian3 = require('Cesium/Core/Cartesian3');
6 | var Color = require('Cesium/Core/Color');
7 | var defined = require('Cesium/Core/defined');
8 | var destroyObject = require('Cesium/Core/destroyObject');
9 | var DeveloperError = require('Cesium/Core/DeveloperError');
10 | var CesiumMath = require('Cesium/Core/Math');
11 | var Matrix3 = require('Cesium/Core/Matrix3');
12 | var Matrix4 = require('Cesium/Core/Matrix4');
13 | var Quaternion = require('Cesium/Core/Quaternion');
14 | var MaterialProperty = require('Cesium/DataSources/MaterialProperty');
15 | var Property = require('Cesium/DataSources/Property');
16 |
17 | var RectangularPyramidSensorVolume = require('./rectangular-pyramid-sensor-volume');
18 | var removePrimitive = require('../util/remove-primitive');
19 |
20 | var defaultIntersectionColor = Color.WHITE;
21 | var defaultIntersectionWidth = 1.0;
22 | var defaultRadius = Number.POSITIVE_INFINITY;
23 |
24 | var matrix3Scratch = new Matrix3();
25 | var cachedPosition = new Cartesian3();
26 | var cachedOrientation = new Quaternion();
27 |
28 | /**
29 | * A {@link Visualizer} which maps {@link Entity#rectangularSensor} to a {@link RectangularSensor}.
30 | * @alias RectangularSensorVisualizer
31 | * @constructor
32 | *
33 | * @param {Scene} scene The scene the primitives will be rendered in.
34 | * @param {EntityCollection} entityCollection The entityCollection to visualize.
35 | */
36 | var RectangularSensorVisualizer = function(scene, entityCollection) {
37 | // >>includeStart('debug', pragmas.debug);
38 | if (!defined(scene)) {
39 | throw new DeveloperError('scene is required.');
40 | }
41 | if (!defined(entityCollection)) {
42 | throw new DeveloperError('entityCollection is required.');
43 | }
44 | // >>includeEnd('debug');
45 |
46 | entityCollection.collectionChanged.addEventListener(RectangularSensorVisualizer.prototype._onCollectionChanged, this);
47 |
48 | this._scene = scene;
49 | this._primitives = scene.primitives;
50 | this._entityCollection = entityCollection;
51 | this._hash = {};
52 | this._entitiesToVisualize = new AssociativeArray();
53 |
54 | this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
55 | };
56 |
57 | /**
58 | * Updates the primitives created by this visualizer to match their
59 | * Entity counterpart at the given time.
60 | *
61 | * @param {JulianDate} time The time to update to.
62 | * @returns {Boolean} This function always returns true.
63 | */
64 | RectangularSensorVisualizer.prototype.update = function(time) {
65 | // >>includeStart('debug', pragmas.debug);
66 | if (!defined(time)) {
67 | throw new DeveloperError('time is required.');
68 | }
69 | // >>includeEnd('debug');
70 |
71 | var entities = this._entitiesToVisualize.values;
72 | var hash = this._hash;
73 | var primitives = this._primitives;
74 |
75 | for (var i = 0, len = entities.length; i < len; i++) {
76 | var entity = entities[i];
77 | var rectangularSensorGraphics = entity._rectangularSensor;
78 |
79 | var position;
80 | var orientation;
81 | var data = hash[entity.id];
82 | var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(rectangularSensorGraphics._show, time, true);
83 |
84 | if (show) {
85 | position = Property.getValueOrUndefined(entity._position, time, cachedPosition);
86 | orientation = Property.getValueOrUndefined(entity._orientation, time, cachedOrientation);
87 | show = defined(position) && defined(orientation);
88 | }
89 |
90 | if (!show) {
91 | // don't bother creating or updating anything else
92 | if (defined(data)) {
93 | data.primitive.show = false;
94 | }
95 | continue;
96 | }
97 |
98 | var primitive = defined(data) ? data.primitive : undefined;
99 | if (!defined(primitive)) {
100 | primitive = new RectangularPyramidSensorVolume();
101 | primitive.id = entity;
102 | primitives.add(primitive);
103 |
104 | data = {
105 | primitive: primitive,
106 | position: undefined,
107 | orientation: undefined
108 | };
109 | hash[entity.id] = data;
110 | }
111 |
112 | if (!Cartesian3.equals(position, data.position) || !Quaternion.equals(orientation, data.orientation)) {
113 | Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, matrix3Scratch), position, primitive.modelMatrix);
114 | data.position = Cartesian3.clone(position, data.position);
115 | data.orientation = Quaternion.clone(orientation, data.orientation);
116 | }
117 |
118 | primitive.show = true;
119 | primitive.xHalfAngle = Property.getValueOrDefault(rectangularSensorGraphics._xHalfAngle, time, CesiumMath.PI_OVER_TWO);
120 | primitive.yHalfAngle = Property.getValueOrDefault(rectangularSensorGraphics._yHalfAngle, time, CesiumMath.PI_OVER_TWO);
121 | primitive.radius = Property.getValueOrDefault(rectangularSensorGraphics._radius, time, defaultRadius);
122 | primitive.lateralSurfaceMaterial = MaterialProperty.getValue(time, rectangularSensorGraphics._lateralSurfaceMaterial, primitive.lateralSurfaceMaterial);
123 | primitive.intersectionColor = Property.getValueOrClonedDefault(rectangularSensorGraphics._intersectionColor, time, defaultIntersectionColor, primitive.intersectionColor);
124 | primitive.intersectionWidth = Property.getValueOrDefault(rectangularSensorGraphics._intersectionWidth, time, defaultIntersectionWidth);
125 | }
126 | return true;
127 | };
128 |
129 | /**
130 | * Returns true if this object was destroyed; otherwise, false.
131 | *
132 | * @returns {Boolean} True if this object was destroyed; otherwise, false.
133 | */
134 | RectangularSensorVisualizer.prototype.isDestroyed = function() {
135 | return false;
136 | };
137 |
138 | /**
139 | * Removes and destroys all primitives created by this instance.
140 | */
141 | RectangularSensorVisualizer.prototype.destroy = function() {
142 | var entities = this._entitiesToVisualize.values;
143 | var hash = this._hash;
144 | var primitives = this._primitives;
145 | for (var i = entities.length - 1; i > -1; i--) {
146 | removePrimitive(entities[i], hash, primitives);
147 | }
148 | return destroyObject(this);
149 | };
150 |
151 | /**
152 | * @private
153 | */
154 | RectangularSensorVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
155 | var i;
156 | var entity;
157 | var entities = this._entitiesToVisualize;
158 | var hash = this._hash;
159 | var primitives = this._primitives;
160 |
161 | for (i = added.length - 1; i > -1; i--) {
162 | entity = added[i];
163 | if (defined(entity._rectangularSensor) && defined(entity._position) && defined(entity._orientation)) {
164 | entities.set(entity.id, entity);
165 | }
166 | }
167 |
168 | for (i = changed.length - 1; i > -1; i--) {
169 | entity = changed[i];
170 | if (defined(entity._rectangularSensor) && defined(entity._position) && defined(entity._orientation)) {
171 | entities.set(entity.id, entity);
172 | } else {
173 | removePrimitive(entity, hash, primitives);
174 | entities.remove(entity.id);
175 | }
176 | }
177 |
178 | for (i = removed.length - 1; i > -1; i--) {
179 | entity = removed[i];
180 | removePrimitive(entity, hash, primitives);
181 | entities.remove(entity.id);
182 | }
183 | };
184 |
185 | return RectangularSensorVisualizer;
186 | });
187 |
--------------------------------------------------------------------------------
/lib/initialize.js:
--------------------------------------------------------------------------------
1 | define(function(require) {
2 | 'use strict';
3 |
4 | var Cartesian3 = require('Cesium/Core/Cartesian3');
5 | var Color = require('Cesium/Core/Color');
6 | var defined = require('Cesium/Core/defined');
7 | var Spherical = require('Cesium/Core/Spherical');
8 | var TimeInterval = require('Cesium/Core/TimeInterval');
9 |
10 | var CzmlDataSource = require('Cesium/DataSources/CzmlDataSource');
11 | var DataSourceDisplay = require('Cesium/DataSources/DataSourceDisplay');
12 |
13 | var ConicSensorGraphics = require('./conic/conic-sensor-graphics');
14 | var ConicSensorVisualizer = require('./conic/conic-sensor-visualizer');
15 | var CustomPatternSensorGraphics = require('./custom/custom-pattern-sensor-graphics');
16 | var CustomPatternSensorVisualizer = require('./custom/custom-pattern-sensor-visualizer');
17 | var RectangularSensorGraphics = require('./rectangular/rectangular-sensor-graphics');
18 | var RectangularSensorVisualizer = require('./rectangular/rectangular-sensor-visualizer');
19 |
20 | var processPacketData = CzmlDataSource.processPacketData;
21 | var processMaterialPacketData = CzmlDataSource.processMaterialPacketData;
22 |
23 | function processDirectionData(customPatternSensor, directions, interval, sourceUri, entityCollection) {
24 | var i;
25 | var len;
26 | var values = [];
27 | var unitSphericals = directions.unitSpherical;
28 | var sphericals = directions.spherical;
29 | var unitCartesians = directions.unitCartesian;
30 | var cartesians = directions.cartesian;
31 |
32 | if (defined(unitSphericals)) {
33 | for (i = 0, len = unitSphericals.length; i < len; i += 2) {
34 | values.push(new Spherical(unitSphericals[i], unitSphericals[i + 1]));
35 | }
36 | directions.array = values;
37 | } else if (defined(sphericals)) {
38 | for (i = 0, len = sphericals.length; i < len; i += 3) {
39 | values.push(new Spherical(sphericals[i], sphericals[i + 1], sphericals[i + 2]));
40 | }
41 | directions.array = values;
42 | } else if (defined(unitCartesians)) {
43 | for (i = 0, len = unitCartesians.length; i < len; i += 3) {
44 | var tmp = Spherical.fromCartesian3(new Cartesian3(unitCartesians[i], unitCartesians[i + 1], unitCartesians[i + 2]));
45 | Spherical.normalize(tmp, tmp);
46 | values.push(tmp);
47 | }
48 | directions.array = values;
49 | } else if (defined(cartesians)) {
50 | for (i = 0, len = cartesians.length; i < len; i += 3) {
51 | values.push(Spherical.fromCartesian3(new Cartesian3(cartesians[i], cartesians[i + 1], cartesians[i + 2])));
52 | }
53 | directions.array = values;
54 | }
55 | processPacketData(Array, customPatternSensor, 'directions', directions, interval, sourceUri, entityCollection);
56 | }
57 |
58 | function processCommonSensorProperties(sensor, sensorData, interval, sourceUri, entityCollection) {
59 | processPacketData(Boolean, sensor, 'show', sensorData.show, interval, sourceUri, entityCollection);
60 | processPacketData(Number, sensor, 'radius', sensorData.radius, interval, sourceUri, entityCollection);
61 | processPacketData(Boolean, sensor, 'showIntersection', sensorData.showIntersection, interval, sourceUri, entityCollection);
62 | processPacketData(Color, sensor, 'intersectionColor', sensorData.intersectionColor, interval, sourceUri, entityCollection);
63 | processPacketData(Number, sensor, 'intersectionWidth', sensorData.intersectionWidth, interval, sourceUri, entityCollection);
64 | processMaterialPacketData(sensor, 'lateralSurfaceMaterial', sensorData.lateralSurfaceMaterial, interval, sourceUri, entityCollection);
65 | }
66 |
67 | var iso8601Scratch = {
68 | iso8601: undefined
69 | };
70 |
71 | function processConicSensor(entity, packet, entityCollection, sourceUri) {
72 | var conicSensorData = packet.agi_conicSensor;
73 | if (!defined(conicSensorData)) {
74 | return;
75 | }
76 |
77 | var interval;
78 | var intervalString = conicSensorData.interval;
79 | if (defined(intervalString)) {
80 | iso8601Scratch.iso8601 = intervalString;
81 | interval = TimeInterval.fromIso8601(iso8601Scratch);
82 | }
83 |
84 | var conicSensor = entity.conicSensor;
85 | if (!defined(conicSensor)) {
86 | entity.addProperty('conicSensor');
87 | conicSensor = new ConicSensorGraphics();
88 | entity.conicSensor = conicSensor;
89 | }
90 |
91 | processCommonSensorProperties(conicSensor, conicSensorData, interval, sourceUri, entityCollection);
92 | processPacketData(Number, conicSensor, 'innerHalfAngle', conicSensorData.innerHalfAngle, interval, sourceUri, entityCollection);
93 | processPacketData(Number, conicSensor, 'outerHalfAngle', conicSensorData.outerHalfAngle, interval, sourceUri, entityCollection);
94 | processPacketData(Number, conicSensor, 'minimumClockAngle', conicSensorData.minimumClockAngle, interval, sourceUri, entityCollection);
95 | processPacketData(Number, conicSensor, 'maximumClockAngle', conicSensorData.maximumClockAngle, interval, sourceUri, entityCollection);
96 | }
97 |
98 | function processCustomPatternSensor(entity, packet, entityCollection, sourceUri) {
99 | var customPatternSensorData = packet.agi_customPatternSensor;
100 | if (!defined(customPatternSensorData)) {
101 | return;
102 | }
103 |
104 | var interval;
105 | var intervalString = customPatternSensorData.interval;
106 | if (defined(intervalString)) {
107 | iso8601Scratch.iso8601 = intervalString;
108 | interval = TimeInterval.fromIso8601(iso8601Scratch);
109 | }
110 |
111 | var customPatternSensor = entity.customPatternSensor;
112 | if (!defined(customPatternSensor)) {
113 | entity.addProperty('customPatternSensor');
114 | customPatternSensor = new CustomPatternSensorGraphics();
115 | entity.customPatternSensor = customPatternSensor;
116 | }
117 |
118 | processCommonSensorProperties(customPatternSensor, customPatternSensorData, interval, sourceUri, entityCollection);
119 |
120 | // The directions property is a special case value that can be an array of unitSpherical or unit Cartesians.
121 | // We pre-process this into Spherical instances and then process it like any other array.
122 | var directions = customPatternSensorData.directions;
123 | if (defined(directions)) {
124 | if (Array.isArray(directions)) {
125 | var length = directions.length;
126 | for (var i = 0; i < length; i++) {
127 | processDirectionData(customPatternSensor, directions[i], interval, sourceUri, entityCollection);
128 | }
129 | } else {
130 | processDirectionData(customPatternSensor, directions, interval, sourceUri, entityCollection);
131 | }
132 | }
133 | }
134 |
135 | function processRectangularSensor(entity, packet, entityCollection, sourceUri) {
136 | var rectangularSensorData = packet.agi_rectangularSensor;
137 | if (!defined(rectangularSensorData)) {
138 | return;
139 | }
140 |
141 | var interval;
142 | var intervalString = rectangularSensorData.interval;
143 | if (defined(intervalString)) {
144 | iso8601Scratch.iso8601 = intervalString;
145 | interval = TimeInterval.fromIso8601(iso8601Scratch);
146 | }
147 |
148 | var rectangularSensor = entity.rectangularSensor;
149 | if (!defined(rectangularSensor)) {
150 | entity.addProperty('rectangularSensor');
151 | rectangularSensor = new RectangularSensorGraphics();
152 | entity.rectangularSensor = rectangularSensor;
153 | }
154 |
155 | processCommonSensorProperties(rectangularSensor, rectangularSensorData, interval, sourceUri, entityCollection);
156 | processPacketData(Number, rectangularSensor, 'xHalfAngle', rectangularSensorData.xHalfAngle, interval, sourceUri, entityCollection);
157 | processPacketData(Number, rectangularSensor, 'yHalfAngle', rectangularSensorData.yHalfAngle, interval, sourceUri, entityCollection);
158 | }
159 |
160 | var initialized = false;
161 | return function initialize() {
162 | if (initialized) {
163 | return;
164 | }
165 |
166 | CzmlDataSource.updaters.push(processConicSensor, processCustomPatternSensor, processRectangularSensor);
167 |
168 | var originalDefaultVisualizersCallback = DataSourceDisplay.defaultVisualizersCallback;
169 | DataSourceDisplay.defaultVisualizersCallback = function(scene, entityCluster, dataSource) {
170 | var entities = dataSource.entities;
171 | var array = originalDefaultVisualizersCallback(scene, entityCluster, dataSource);
172 | return array.concat([
173 | new ConicSensorVisualizer(scene, entities),
174 | new CustomPatternSensorVisualizer(scene, entities),
175 | new RectangularSensorVisualizer(scene, entities)
176 | ]);
177 | };
178 |
179 | initialized = true;
180 | };
181 | });
182 |
--------------------------------------------------------------------------------
/test/rectangular/rectangular-sensor-visualizer-webgl-spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-nested-callbacks */
2 | define([
3 | 'rectangular/rectangular-sensor-graphics',
4 | 'rectangular/rectangular-sensor-visualizer',
5 | 'Cesium/Core/Cartesian3',
6 | 'Cesium/Core/Color',
7 | 'Cesium/Core/JulianDate',
8 | 'Cesium/Core/Math',
9 | 'Cesium/Core/Matrix3',
10 | 'Cesium/Core/Matrix4',
11 | 'Cesium/Core/Quaternion',
12 | 'Cesium/Core/Spherical',
13 | 'Cesium/DataSources/ColorMaterialProperty',
14 | 'Cesium/DataSources/ConstantProperty',
15 | 'Cesium/DataSources/EntityCollection',
16 | '../util/create-scene',
17 | '../matchers/add-to-throw-developer-error-matcher'
18 | ], function(
19 | RectangularSensorGraphics,
20 | RectangularSensorVisualizer,
21 | Cartesian3,
22 | Color,
23 | JulianDate,
24 | CesiumMath,
25 | Matrix3,
26 | Matrix4,
27 | Quaternion,
28 | Spherical,
29 | ColorMaterialProperty,
30 | ConstantProperty,
31 | EntityCollection,
32 | createScene,
33 | addToThrowDeveloperErrorMatcher
34 | ) {
35 | 'use strict';
36 |
37 | /* global describe, it, beforeAll, afterAll, beforeEach, afterEach, expect */
38 |
39 | describe('rectangular sensor visualizer', function() {
40 | var scene;
41 | var visualizer;
42 |
43 | beforeAll(function() {
44 | scene = createScene();
45 | });
46 |
47 | afterAll(function() {
48 | scene.destroyForSpecs();
49 | });
50 |
51 | beforeEach(addToThrowDeveloperErrorMatcher);
52 |
53 | afterEach(function() {
54 | visualizer = visualizer && visualizer.destroy();
55 | });
56 |
57 | describe('constructor', function() {
58 | it('should throw if no scene is passed', function() {
59 | expect(function() {
60 | return new RectangularSensorVisualizer();
61 | }).toThrowDeveloperError();
62 | });
63 | });
64 |
65 | describe('update', function() {
66 | it('should throw if no time specified', function() {
67 | var entityCollection = new EntityCollection();
68 | visualizer = new RectangularSensorVisualizer(scene, entityCollection);
69 | expect(function() {
70 | visualizer.update();
71 | }).toThrowDeveloperError();
72 | });
73 | });
74 |
75 | describe('isDestroy', function() {
76 | it('should return false until destroyed', function() {
77 | var entityCollection = new EntityCollection();
78 | visualizer = new RectangularSensorVisualizer(scene, entityCollection);
79 | expect(visualizer.isDestroyed()).toEqual(false);
80 | visualizer.destroy();
81 | expect(visualizer.isDestroyed()).toEqual(true);
82 | visualizer = undefined;
83 | });
84 | });
85 |
86 | it('should not create a primitive from an object with no rectangularSensor', function() {
87 | var entityCollection = new EntityCollection();
88 | visualizer = new RectangularSensorVisualizer(scene, entityCollection);
89 |
90 | var testObject = entityCollection.getOrCreateEntity('test');
91 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
92 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
93 | visualizer.update(JulianDate.now());
94 | expect(scene.primitives.length).toEqual(0);
95 | });
96 |
97 | it('should not create a primitive from an object with no position', function() {
98 | var entityCollection = new EntityCollection();
99 | visualizer = new RectangularSensorVisualizer(scene, entityCollection);
100 |
101 | var testObject = entityCollection.getOrCreateEntity('test');
102 | testObject.addProperty('rectangularSensor');
103 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
104 | var rectangularSensor = new RectangularSensorGraphics();
105 | rectangularSensor.xHalfAngle = new ConstantProperty(0.1);
106 | rectangularSensor.yHalfAngle = new ConstantProperty(0.2);
107 | testObject.rectangularSensor = rectangularSensor;
108 | visualizer.update(JulianDate.now());
109 | expect(scene.primitives.length).toEqual(0);
110 | });
111 |
112 | it('should not create a primitive from an object with no orientation', function() {
113 | var entityCollection = new EntityCollection();
114 | visualizer = new RectangularSensorVisualizer(scene, entityCollection);
115 |
116 | var testObject = entityCollection.getOrCreateEntity('test');
117 | testObject.addProperty('rectangularSensor');
118 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
119 | var rectangularSensor = new RectangularSensorGraphics();
120 | rectangularSensor.xHalfAngle = new ConstantProperty(0.1);
121 | rectangularSensor.yHalfAngle = new ConstantProperty(0.2);
122 | testObject.rectangularSensor = rectangularSensor;
123 | visualizer.update(JulianDate.now());
124 | expect(scene.primitives.length).toEqual(0);
125 | });
126 |
127 | it('should cause a sensor to be created and updated', function() {
128 | var time = JulianDate.now();
129 | var entityCollection = new EntityCollection();
130 | visualizer = new RectangularSensorVisualizer(scene, entityCollection);
131 |
132 | var testObject = entityCollection.getOrCreateEntity('test');
133 | testObject.addProperty('rectangularSensor');
134 | testObject.show = true;
135 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
136 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, Math.sin(CesiumMath.PI_OVER_FOUR), Math.cos(CesiumMath.PI_OVER_FOUR)));
137 |
138 | var rectangularSensor = new RectangularSensorGraphics();
139 | rectangularSensor.xHalfAngle = new ConstantProperty(0.1);
140 | rectangularSensor.yHalfAngle = new ConstantProperty(0.2);
141 | rectangularSensor.intersectionColor = new ConstantProperty(new Color(0.1, 0.2, 0.3, 0.4));
142 | rectangularSensor.intersectionWidth = new ConstantProperty(0.5);
143 | rectangularSensor.showIntersection = new ConstantProperty(true);
144 | rectangularSensor.radius = new ConstantProperty(123.5);
145 | rectangularSensor.show = new ConstantProperty(true);
146 | rectangularSensor.lateralSurfaceMaterial = new ColorMaterialProperty(Color.WHITE);
147 | testObject.rectangularSensor = rectangularSensor;
148 | visualizer.update(time);
149 |
150 | expect(scene.primitives.length).toEqual(1);
151 | var p = scene.primitives.get(0);
152 | expect(p.intersectionColor).toEqual(testObject.rectangularSensor.intersectionColor.getValue(time));
153 | expect(p.intersectionWidth).toEqual(testObject.rectangularSensor.intersectionWidth.getValue(time));
154 | expect(p.showIntersection).toEqual(testObject.rectangularSensor.showIntersection.getValue(time));
155 | expect(p.radius).toEqual(testObject.rectangularSensor.radius.getValue(time));
156 | expect(p.modelMatrix).toEqual(Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(testObject.orientation.getValue(time)), testObject.position.getValue(time)));
157 | expect(p.show).toEqual(testObject.rectangularSensor.show.getValue(time));
158 | expect(p.lateralSurfaceMaterial.uniforms).toEqual(testObject.rectangularSensor.lateralSurfaceMaterial.getValue(time));
159 |
160 | testObject.show = false;
161 | visualizer.update(time);
162 | expect(p.show).toBe(false);
163 |
164 | testObject.show = true;
165 | visualizer.update(time);
166 | expect(p.show).toBe(true);
167 |
168 | rectangularSensor.show.setValue(false);
169 | visualizer.update(time);
170 | expect(p.show).toBe(false);
171 | });
172 |
173 | it('should remove primitives', function() {
174 | var entityCollection = new EntityCollection();
175 | visualizer = new RectangularSensorVisualizer(scene, entityCollection);
176 |
177 | var testObject = entityCollection.getOrCreateEntity('test');
178 | testObject.addProperty('rectangularSensor');
179 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
180 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
181 | var rectangularSensor = new RectangularSensorGraphics();
182 | rectangularSensor.xHalfAngle = new ConstantProperty(0.1);
183 | rectangularSensor.yHalfAngle = new ConstantProperty(0.2);
184 | testObject.rectangularSensor = rectangularSensor;
185 |
186 | var time = JulianDate.now();
187 | expect(scene.primitives.length).toEqual(0);
188 | visualizer.update(time);
189 | expect(scene.primitives.length).toEqual(1);
190 | expect(scene.primitives.get(0).show).toEqual(true);
191 | entityCollection.removeAll();
192 | visualizer.update(time);
193 | expect(scene.primitives.length).toEqual(0);
194 | });
195 |
196 | it('should set entity property', function() {
197 | var entityCollection = new EntityCollection();
198 | visualizer = new RectangularSensorVisualizer(scene, entityCollection);
199 |
200 | var testObject = entityCollection.getOrCreateEntity('test');
201 | testObject.addProperty('rectangularSensor');
202 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
203 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
204 | var rectangularSensor = new RectangularSensorGraphics();
205 | rectangularSensor.xHalfAngle = new ConstantProperty(0.1);
206 | rectangularSensor.yHalfAngle = new ConstantProperty(0.2);
207 | testObject.rectangularSensor = rectangularSensor;
208 |
209 | var time = JulianDate.now();
210 | visualizer.update(time);
211 | expect(scene.primitives.get(0).id).toEqual(testObject);
212 | });
213 | });
214 | }, 'WebGL');
215 |
--------------------------------------------------------------------------------
/test/custom/custom-pattern-sensor-visualizer-webgl-spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-nested-callbacks */
2 | define([
3 | 'custom/custom-pattern-sensor-graphics',
4 | 'custom/custom-pattern-sensor-visualizer',
5 | 'Cesium/Core/Cartesian3',
6 | 'Cesium/Core/Color',
7 | 'Cesium/Core/JulianDate',
8 | 'Cesium/Core/Math',
9 | 'Cesium/Core/Matrix3',
10 | 'Cesium/Core/Matrix4',
11 | 'Cesium/Core/Quaternion',
12 | 'Cesium/Core/Spherical',
13 | 'Cesium/DataSources/ColorMaterialProperty',
14 | 'Cesium/DataSources/ConstantProperty',
15 | 'Cesium/DataSources/EntityCollection',
16 | '../util/create-scene',
17 | '../matchers/add-to-throw-developer-error-matcher'
18 | ], function(
19 | CustomPatternSensorGraphics,
20 | CustomPatternSensorVisualizer,
21 | Cartesian3,
22 | Color,
23 | JulianDate,
24 | CesiumMath,
25 | Matrix3,
26 | Matrix4,
27 | Quaternion,
28 | Spherical,
29 | ColorMaterialProperty,
30 | ConstantProperty,
31 | EntityCollection,
32 | createScene,
33 | addToThrowDeveloperErrorMatcher
34 | ) {
35 | 'use strict';
36 |
37 | /* global describe, it, beforeAll, afterAll, beforeEach, afterEach, expect */
38 |
39 | describe('custom pattern sensor visualizer', function() {
40 | var scene;
41 | var visualizer;
42 |
43 | beforeAll(function() {
44 | scene = createScene();
45 | });
46 |
47 | afterAll(function() {
48 | scene.destroyForSpecs();
49 | });
50 |
51 | beforeEach(addToThrowDeveloperErrorMatcher);
52 |
53 | afterEach(function() {
54 | visualizer = visualizer && visualizer.destroy();
55 | });
56 |
57 | describe('constructor', function() {
58 | it('should throw if no scene is passed', function() {
59 | expect(function() {
60 | return new CustomPatternSensorVisualizer();
61 | }).toThrowDeveloperError();
62 | });
63 | });
64 |
65 | describe('isDestroy', function() {
66 | it('should return false until destroyed', function() {
67 | var entityCollection = new EntityCollection();
68 | visualizer = new CustomPatternSensorVisualizer(scene, entityCollection);
69 | expect(visualizer.isDestroyed()).toEqual(false);
70 | visualizer.destroy();
71 | expect(visualizer.isDestroyed()).toEqual(true);
72 | visualizer = undefined;
73 | });
74 | });
75 |
76 | describe('update', function() {
77 | it('should throw if no time specified', function() {
78 | var entityCollection = new EntityCollection();
79 | visualizer = new CustomPatternSensorVisualizer(scene, entityCollection);
80 | expect(function() {
81 | visualizer.update();
82 | }).toThrowDeveloperError();
83 | });
84 | });
85 |
86 | it('should not create a primitive from an object with no customPatternSensor', function() {
87 | var entityCollection = new EntityCollection();
88 | visualizer = new CustomPatternSensorVisualizer(scene, entityCollection);
89 |
90 | var testObject = entityCollection.getOrCreateEntity('test');
91 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
92 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
93 | visualizer.update(JulianDate.now());
94 | expect(scene.primitives.length).toEqual(0);
95 | });
96 |
97 | it('should not create a primitive from an object with no position', function() {
98 | var entityCollection = new EntityCollection();
99 | visualizer = new CustomPatternSensorVisualizer(scene, entityCollection);
100 |
101 | var testObject = entityCollection.getOrCreateEntity('test');
102 | testObject.addProperty('customPatternSensor');
103 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
104 | var customPatternSensor = new CustomPatternSensorGraphics();
105 | customPatternSensor.directions = new ConstantProperty([new Spherical(0, 0, 0), new Spherical(1, 0, 0), new Spherical(2, 0, 0), new Spherical(3, 0, 0)]);
106 | testObject.customPatternSensor = customPatternSensor;
107 | visualizer.update(JulianDate.now());
108 | expect(scene.primitives.length).toEqual(0);
109 | });
110 |
111 | it('should not create a primitive from object with no orientation', function() {
112 | var entityCollection = new EntityCollection();
113 | visualizer = new CustomPatternSensorVisualizer(scene, entityCollection);
114 |
115 | var testObject = entityCollection.getOrCreateEntity('test');
116 | testObject.addProperty('customPatternSensor');
117 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
118 | var customPatternSensor = new CustomPatternSensorGraphics();
119 | customPatternSensor.directions = new ConstantProperty([new Spherical(0, 0, 0), new Spherical(1, 0, 0), new Spherical(2, 0, 0), new Spherical(3, 0, 0)]);
120 | testObject.customPatternSensor = customPatternSensor;
121 | visualizer.update(JulianDate.now());
122 | expect(scene.primitives.length).toEqual(0);
123 | });
124 |
125 | it('should cause a CustomSensor to be created and updated', function() {
126 | var time = JulianDate.now();
127 | var entityCollection = new EntityCollection();
128 | visualizer = new CustomPatternSensorVisualizer(scene, entityCollection);
129 |
130 | var testObject = entityCollection.getOrCreateEntity('test');
131 | testObject.addProperty('customPatternSensor');
132 | testObject.show = true;
133 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
134 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, Math.sin(CesiumMath.PI_OVER_FOUR), Math.cos(CesiumMath.PI_OVER_FOUR)));
135 |
136 | var customPatternSensor = new CustomPatternSensorGraphics();
137 | customPatternSensor.directions = new ConstantProperty([new Spherical(0, 0, 0), new Spherical(1, 0, 0), new Spherical(2, 0, 0), new Spherical(3, 0, 0)]);
138 | customPatternSensor.intersectionColor = new ConstantProperty(new Color(0.1, 0.2, 0.3, 0.4));
139 | customPatternSensor.intersectionWidth = new ConstantProperty(0.5);
140 | customPatternSensor.showIntersection = new ConstantProperty(true);
141 | customPatternSensor.radius = new ConstantProperty(123.5);
142 | customPatternSensor.show = new ConstantProperty(true);
143 | customPatternSensor.lateralSurfaceMaterial = new ColorMaterialProperty(Color.WHITE);
144 | testObject.customPatternSensor = customPatternSensor;
145 | visualizer.update(time);
146 |
147 | expect(scene.primitives.length).toEqual(1);
148 | var p = scene.primitives.get(0);
149 | expect(p.intersectionColor).toEqual(testObject.customPatternSensor.intersectionColor.getValue(time));
150 | expect(p.intersectionWidth).toEqual(testObject.customPatternSensor.intersectionWidth.getValue(time));
151 | expect(p.showIntersection).toEqual(testObject.customPatternSensor.showIntersection.getValue(time));
152 | expect(p.radius).toEqual(testObject.customPatternSensor.radius.getValue(time));
153 | expect(p.modelMatrix).toEqual(Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(testObject.orientation.getValue(time)), testObject.position.getValue(time)));
154 | expect(p.show).toEqual(testObject.customPatternSensor.show.getValue(time));
155 | expect(p.lateralSurfaceMaterial.uniforms).toEqual(testObject.customPatternSensor.lateralSurfaceMaterial.getValue(time));
156 |
157 | testObject.show = false;
158 | visualizer.update(time);
159 | expect(p.show).toBe(false);
160 |
161 | testObject.show = true;
162 | visualizer.update(time);
163 | expect(p.show).toBe(true);
164 |
165 | customPatternSensor.show.setValue(false);
166 | visualizer.update(time);
167 | expect(p.show).toBe(false);
168 | });
169 |
170 | it('should remove primitives', function() {
171 | var entityCollection = new EntityCollection();
172 | visualizer = new CustomPatternSensorVisualizer(scene, entityCollection);
173 |
174 | var testObject = entityCollection.getOrCreateEntity('test');
175 | testObject.addProperty('customPatternSensor');
176 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
177 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
178 | var customPatternSensor = new CustomPatternSensorGraphics();
179 | customPatternSensor.directions = new ConstantProperty([new Spherical(0, 0, 0), new Spherical(1, 0, 0), new Spherical(2, 0, 0), new Spherical(3, 0, 0)]);
180 | testObject.customPatternSensor = customPatternSensor;
181 |
182 | var time = JulianDate.now();
183 | expect(scene.primitives.length).toEqual(0);
184 | visualizer.update(time);
185 | expect(scene.primitives.length).toEqual(1);
186 | expect(scene.primitives.get(0).show).toEqual(true);
187 | entityCollection.removeAll();
188 | visualizer.update(time);
189 | expect(scene.primitives.length).toEqual(0);
190 | });
191 |
192 | it('should set entity property', function() {
193 | var entityCollection = new EntityCollection();
194 | visualizer = new CustomPatternSensorVisualizer(scene, entityCollection);
195 |
196 | var testObject = entityCollection.getOrCreateEntity('test');
197 | testObject.addProperty('customPatternSensor');
198 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
199 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
200 | var customPatternSensor = new CustomPatternSensorGraphics();
201 | customPatternSensor.directions = new ConstantProperty([new Spherical(0, 0, 0), new Spherical(1, 0, 0), new Spherical(2, 0, 0), new Spherical(3, 0, 0)]);
202 | testObject.customPatternSensor = customPatternSensor;
203 |
204 | var time = JulianDate.now();
205 | visualizer.update(time);
206 | expect(scene.primitives.get(0).id).toEqual(testObject);
207 | });
208 | });
209 | });
210 |
--------------------------------------------------------------------------------
/lib/conic/conic-sensor-visualizer.js:
--------------------------------------------------------------------------------
1 | define(function(require) {
2 | 'use strict';
3 |
4 | var AssociativeArray = require('Cesium/Core/AssociativeArray');
5 | var Cartesian3 = require('Cesium/Core/Cartesian3');
6 | var Color = require('Cesium/Core/Color');
7 | var defined = require('Cesium/Core/defined');
8 | var destroyObject = require('Cesium/Core/destroyObject');
9 | var DeveloperError = require('Cesium/Core/DeveloperError');
10 | var CesiumMath = require('Cesium/Core/Math');
11 | var Matrix3 = require('Cesium/Core/Matrix3');
12 | var Matrix4 = require('Cesium/Core/Matrix4');
13 | var Quaternion = require('Cesium/Core/Quaternion');
14 | var Spherical = require('Cesium/Core/Spherical');
15 | var MaterialProperty = require('Cesium/DataSources/MaterialProperty');
16 | var Property = require('Cesium/DataSources/Property');
17 |
18 | var CustomSensorVolume = require('../custom/custom-sensor-volume');
19 | var removePrimitive = require('../util/remove-primitive');
20 |
21 | var defaultIntersectionColor = Color.WHITE;
22 | var defaultIntersectionWidth = 1.0;
23 | var defaultRadius = Number.POSITIVE_INFINITY;
24 |
25 | var matrix3Scratch = new Matrix3();
26 | var cachedPosition = new Cartesian3();
27 | var cachedOrientation = new Quaternion();
28 |
29 | function assignSpherical(index, array, clock, cone) {
30 | var spherical = array[index];
31 | if (!defined(spherical)) {
32 | spherical = new Spherical();
33 | array[index] = spherical;
34 | }
35 | spherical.clock = clock;
36 | spherical.cone = cone;
37 | spherical.magnitude = 1.0;
38 | }
39 |
40 | function computeDirections(primitive, minimumClockAngle, maximumClockAngle, innerHalfAngle, outerHalfAngle) {
41 | var directions = primitive.directions;
42 | var angle;
43 | var i = 0;
44 | var angleStep = CesiumMath.toRadians(2.0);
45 | if (minimumClockAngle === 0.0 && maximumClockAngle === CesiumMath.TWO_PI) {
46 | // No clock angle limits, so this is just a circle.
47 | // There might be a hole but we're ignoring it for now.
48 | for (angle = 0.0; angle < CesiumMath.TWO_PI; angle += angleStep) {
49 | assignSpherical(i++, directions, angle, outerHalfAngle);
50 | }
51 | } else {
52 | // There are clock angle limits.
53 | for (angle = minimumClockAngle; angle < maximumClockAngle; angle += angleStep) {
54 | assignSpherical(i++, directions, angle, outerHalfAngle);
55 | }
56 | assignSpherical(i++, directions, maximumClockAngle, outerHalfAngle);
57 | if (innerHalfAngle) {
58 | for (angle = maximumClockAngle; angle > minimumClockAngle; angle -= angleStep) {
59 | assignSpherical(i++, directions, angle, innerHalfAngle);
60 | }
61 | assignSpherical(i++, directions, minimumClockAngle, innerHalfAngle);
62 | } else {
63 | assignSpherical(i++, directions, maximumClockAngle, 0.0);
64 | }
65 | }
66 | directions.length = i;
67 | primitive.directions = directions;
68 | }
69 |
70 | /**
71 | * A {@link Visualizer} which maps {@link Entity#conicSensor} to a {@link ConicSensor}.
72 | * @alias ConicSensorVisualizer
73 | * @constructor
74 | *
75 | * @param {Scene} scene The scene the primitives will be rendered in.
76 | * @param {EntityCollection} entityCollection The entityCollection to visualize.
77 | */
78 | var ConicSensorVisualizer = function(scene, entityCollection) {
79 | // >>includeStart('debug', pragmas.debug);
80 | if (!defined(scene)) {
81 | throw new DeveloperError('scene is required.');
82 | }
83 | if (!defined(entityCollection)) {
84 | throw new DeveloperError('entityCollection is required.');
85 | }
86 | // >>includeEnd('debug');
87 |
88 | entityCollection.collectionChanged.addEventListener(ConicSensorVisualizer.prototype._onCollectionChanged, this);
89 |
90 | this._scene = scene;
91 | this._primitives = scene.primitives;
92 | this._entityCollection = entityCollection;
93 | this._hash = {};
94 | this._entitiesToVisualize = new AssociativeArray();
95 |
96 | this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
97 | };
98 |
99 | /**
100 | * Updates the primitives created by this visualizer to match their
101 | * Entity counterpart at the given time.
102 | *
103 | * @param {JulianDate} time The time to update to.
104 | * @returns {Boolean} This function always returns true.
105 | */
106 | ConicSensorVisualizer.prototype.update = function(time) {
107 | // >>includeStart('debug', pragmas.debug);
108 | if (!defined(time)) {
109 | throw new DeveloperError('time is required.');
110 | }
111 | // >>includeEnd('debug');
112 |
113 | var entities = this._entitiesToVisualize.values;
114 | var hash = this._hash;
115 | var primitives = this._primitives;
116 |
117 | for (var i = 0, len = entities.length; i < len; i++) {
118 | var entity = entities[i];
119 | var conicSensorGraphics = entity._conicSensor;
120 |
121 | var position;
122 | var orientation;
123 | var data = hash[entity.id];
124 | var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(conicSensorGraphics._show, time, true);
125 |
126 | if (show) {
127 | position = Property.getValueOrUndefined(entity._position, time, cachedPosition);
128 | orientation = Property.getValueOrUndefined(entity._orientation, time, cachedOrientation);
129 | show = defined(position) && defined(orientation);
130 | }
131 |
132 | if (!show) {
133 | // don't bother creating or updating anything else
134 | if (defined(data)) {
135 | data.primitive.show = false;
136 | }
137 | continue;
138 | }
139 |
140 | var primitive = defined(data) ? data.primitive : undefined;
141 | if (!defined(primitive)) {
142 | primitive = new CustomSensorVolume();
143 | primitive.id = entity;
144 | primitives.add(primitive);
145 |
146 | data = {
147 | primitive: primitive,
148 | position: undefined,
149 | orientation: undefined,
150 | minimumClockAngle: undefined,
151 | maximumClockAngle: undefined,
152 | innerHalfAngle: undefined,
153 | outerHalfAngle: undefined
154 | };
155 | hash[entity.id] = data;
156 | }
157 |
158 | if (!Cartesian3.equals(position, data.position) || !Quaternion.equals(orientation, data.orientation)) {
159 | Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, matrix3Scratch), position, primitive.modelMatrix);
160 | data.position = Cartesian3.clone(position, data.position);
161 | data.orientation = Quaternion.clone(orientation, data.orientation);
162 | }
163 |
164 | primitive.show = true;
165 | var minimumClockAngle = Property.getValueOrDefault(conicSensorGraphics._minimumClockAngle, time, 0);
166 | var maximumClockAngle = Property.getValueOrDefault(conicSensorGraphics._maximumClockAngle, time, CesiumMath.TWO_PI);
167 | var innerHalfAngle = Property.getValueOrDefault(conicSensorGraphics._innerHalfAngle, time, 0);
168 | var outerHalfAngle = Property.getValueOrDefault(conicSensorGraphics._outerHalfAngle, time, Math.PI);
169 |
170 | if (minimumClockAngle !== data.minimumClockAngle ||
171 | maximumClockAngle !== data.maximumClockAngle ||
172 | innerHalfAngle !== data.innerHalfAngle ||
173 | outerHalfAngle !== data.outerHalfAngle
174 | ) {
175 | computeDirections(primitive, minimumClockAngle, maximumClockAngle, innerHalfAngle, outerHalfAngle);
176 | data.innerHalfAngle = innerHalfAngle;
177 | data.maximumClockAngle = maximumClockAngle;
178 | data.outerHalfAngle = outerHalfAngle;
179 | data.minimumClockAngle = minimumClockAngle;
180 | }
181 |
182 | primitive.radius = Property.getValueOrDefault(conicSensorGraphics._radius, time, defaultRadius);
183 | primitive.lateralSurfaceMaterial = MaterialProperty.getValue(time, conicSensorGraphics._lateralSurfaceMaterial, primitive.lateralSurfaceMaterial);
184 | primitive.intersectionColor = Property.getValueOrClonedDefault(conicSensorGraphics._intersectionColor, time, defaultIntersectionColor, primitive.intersectionColor);
185 | primitive.intersectionWidth = Property.getValueOrDefault(conicSensorGraphics._intersectionWidth, time, defaultIntersectionWidth);
186 | }
187 | return true;
188 | };
189 |
190 | /**
191 | * Returns true if this object was destroyed; otherwise, false.
192 | *
193 | * @returns {Boolean} True if this object was destroyed; otherwise, false.
194 | */
195 | ConicSensorVisualizer.prototype.isDestroyed = function() {
196 | return false;
197 | };
198 |
199 | /**
200 | * Removes and destroys all primitives created by this instance.
201 | */
202 | ConicSensorVisualizer.prototype.destroy = function() {
203 | var entities = this._entitiesToVisualize.values;
204 | var hash = this._hash;
205 | var primitives = this._primitives;
206 | for (var i = entities.length - 1; i > -1; i--) {
207 | removePrimitive(entities[i], hash, primitives);
208 | }
209 | return destroyObject(this);
210 | };
211 |
212 | /**
213 | * @private
214 | */
215 | ConicSensorVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
216 | var i;
217 | var entity;
218 | var entities = this._entitiesToVisualize;
219 | var hash = this._hash;
220 | var primitives = this._primitives;
221 |
222 | for (i = added.length - 1; i > -1; i--) {
223 | entity = added[i];
224 | if (defined(entity._conicSensor) && defined(entity._position) && defined(entity._orientation)) {
225 | entities.set(entity.id, entity);
226 | }
227 | }
228 |
229 | for (i = changed.length - 1; i > -1; i--) {
230 | entity = changed[i];
231 | if (defined(entity._conicSensor) && defined(entity._position) && defined(entity._orientation)) {
232 | entities.set(entity.id, entity);
233 | } else {
234 | removePrimitive(entity, hash, primitives);
235 | entities.remove(entity.id);
236 | }
237 | }
238 |
239 | for (i = removed.length - 1; i > -1; i--) {
240 | entity = removed[i];
241 | removePrimitive(entity, hash, primitives);
242 | entities.remove(entity.id);
243 | }
244 | };
245 |
246 | return ConicSensorVisualizer;
247 | });
248 |
--------------------------------------------------------------------------------
/test/conic/conic-sensor-visualizer-webgl-spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-nested-callbacks */
2 | define([
3 | 'conic/conic-sensor-graphics',
4 | 'conic/conic-sensor-visualizer',
5 | 'Cesium/Core/Cartesian3',
6 | 'Cesium/Core/Color',
7 | 'Cesium/Core/JulianDate',
8 | 'Cesium/Core/Math',
9 | 'Cesium/Core/Matrix3',
10 | 'Cesium/Core/Matrix4',
11 | 'Cesium/Core/Quaternion',
12 | 'Cesium/DataSources/ColorMaterialProperty',
13 | 'Cesium/DataSources/ConstantProperty',
14 | 'Cesium/DataSources/EntityCollection',
15 | '../util/create-scene',
16 | '../matchers/add-to-throw-developer-error-matcher'
17 | ], function(
18 | ConicSensorGraphics,
19 | ConicSensorVisualizer,
20 | Cartesian3,
21 | Color,
22 | JulianDate,
23 | CesiumMath,
24 | Matrix3,
25 | Matrix4,
26 | Quaternion,
27 | ColorMaterialProperty,
28 | ConstantProperty,
29 | EntityCollection,
30 | createScene,
31 | addToThrowDeveloperErrorMatcher
32 | ) {
33 | 'use strict';
34 |
35 | /* global describe, it, beforeAll, afterAll, beforeEach, afterEach, expect */
36 |
37 | describe('conic sensor visualizer', function() {
38 | var scene;
39 | var visualizer;
40 |
41 | beforeAll(function() {
42 | scene = createScene();
43 | });
44 |
45 | afterAll(function() {
46 | scene.destroyForSpecs();
47 | });
48 |
49 | beforeEach(addToThrowDeveloperErrorMatcher);
50 |
51 | afterEach(function() {
52 | visualizer = visualizer && visualizer.destroy();
53 | });
54 |
55 | describe('constructor', function() {
56 | it('should throw if no scene is passed', function() {
57 | expect(function() {
58 | return new ConicSensorVisualizer();
59 | }).toThrowDeveloperError();
60 | });
61 | });
62 |
63 | describe('update', function() {
64 | it('should throw if no time specified', function() {
65 | var entityCollection = new EntityCollection();
66 | visualizer = new ConicSensorVisualizer(scene, entityCollection);
67 | expect(function() {
68 | visualizer.update();
69 | }).toThrowDeveloperError();
70 | });
71 | });
72 |
73 | describe('isDestroy', function() {
74 | it('should return false until destroyed', function() {
75 | var entityCollection = new EntityCollection();
76 | visualizer = new ConicSensorVisualizer(scene, entityCollection);
77 | expect(visualizer.isDestroyed()).toEqual(false);
78 | visualizer.destroy();
79 | expect(visualizer.isDestroyed()).toEqual(true);
80 | visualizer = undefined;
81 | });
82 | });
83 |
84 | it('should not create a primitive from an object with no conicSensor', function() {
85 | var entityCollection = new EntityCollection();
86 | visualizer = new ConicSensorVisualizer(scene, entityCollection);
87 |
88 | var testObject = entityCollection.getOrCreateEntity('test');
89 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
90 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
91 | visualizer.update(JulianDate.now());
92 | expect(scene.primitives.length).toEqual(0);
93 | });
94 |
95 | it('should not create a primitive from an object with no position', function() {
96 | var entityCollection = new EntityCollection();
97 | visualizer = new ConicSensorVisualizer(scene, entityCollection);
98 |
99 | var testObject = entityCollection.getOrCreateEntity('test');
100 | testObject.addProperty('conicSensor');
101 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
102 | var conicSensor = new ConicSensorGraphics();
103 | conicSensor.maximumClockAngle = new ConstantProperty(1);
104 | conicSensor.outerHalfAngle = new ConstantProperty(1);
105 | testObject.conicSensor = conicSensor;
106 | visualizer.update(JulianDate.now());
107 | expect(scene.primitives.length).toEqual(0);
108 | });
109 |
110 | it('should not create a primitive from an object with no orientation', function() {
111 | var entityCollection = new EntityCollection();
112 | visualizer = new ConicSensorVisualizer(scene, entityCollection);
113 |
114 | var testObject = entityCollection.getOrCreateEntity('test');
115 | testObject.addProperty('conicSensor');
116 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
117 | var conicSensor = new ConicSensorGraphics();
118 | conicSensor.maximumClockAngle = new ConstantProperty(1);
119 | conicSensor.outerHalfAngle = new ConstantProperty(1);
120 | testObject.conicSensor = conicSensor;
121 | visualizer.update(JulianDate.now());
122 | expect(scene.primitives.length).toEqual(0);
123 | });
124 |
125 | it('should cause a ComplexConicSensor to be created and updated', function() {
126 | var time = JulianDate.now();
127 | var entityCollection = new EntityCollection();
128 | visualizer = new ConicSensorVisualizer(scene, entityCollection);
129 |
130 | var testObject = entityCollection.getOrCreateEntity('test');
131 | testObject.addProperty('conicSensor');
132 | testObject.show = true;
133 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
134 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, Math.sin(CesiumMath.PI_OVER_FOUR), Math.cos(CesiumMath.PI_OVER_FOUR)));
135 |
136 | var conicSensor = new ConicSensorGraphics();
137 | conicSensor.minimumClockAngle = new ConstantProperty(0.1);
138 | conicSensor.maximumClockAngle = new ConstantProperty(0.2);
139 | conicSensor.innerHalfAngle = new ConstantProperty(0.3);
140 | conicSensor.outerHalfAngle = new ConstantProperty(0.4);
141 | conicSensor.intersectionColor = new ConstantProperty(new Color(0.1, 0.2, 0.3, 0.4));
142 | conicSensor.intersectionWidth = new ConstantProperty(0.5);
143 | conicSensor.showIntersection = new ConstantProperty(true);
144 | conicSensor.radius = new ConstantProperty(123.5);
145 | conicSensor.show = new ConstantProperty(true);
146 | conicSensor.lateralSurfaceMaterial = new ColorMaterialProperty(Color.WHITE);
147 |
148 | testObject.conicSensor = conicSensor;
149 |
150 | visualizer.update(time);
151 | expect(scene.primitives.length).toEqual(1);
152 |
153 | var c = scene.primitives.get(0);
154 | expect(c.directions.length).toBeGreaterThan(0);
155 | expect(c.intersectionColor).toEqual(testObject.conicSensor.intersectionColor.getValue(time));
156 | expect(c.intersectionWidth).toEqual(testObject.conicSensor.intersectionWidth.getValue(time));
157 | expect(c.showIntersection).toEqual(testObject.conicSensor.showIntersection.getValue(time));
158 | expect(c.radius).toEqual(testObject.conicSensor.radius.getValue(time));
159 | expect(c.modelMatrix).toEqual(Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(testObject.orientation.getValue(time)), testObject.position.getValue(time)));
160 | expect(c.show).toEqual(testObject.conicSensor.show.getValue(time));
161 | expect(c.lateralSurfaceMaterial.uniforms).toEqual(testObject.conicSensor.lateralSurfaceMaterial.getValue(time));
162 |
163 | testObject.show = false;
164 | visualizer.update(time);
165 | expect(c.show).toBe(false);
166 |
167 | testObject.show = true;
168 | visualizer.update(time);
169 | expect(c.show).toBe(true);
170 |
171 | conicSensor.show.setValue(false);
172 | visualizer.update(time);
173 | expect(c.show).toBe(false);
174 | });
175 |
176 | it('should set IntersectionColor correctly with multiple conicSensors', function() {
177 | var time = JulianDate.now();
178 | var entityCollection = new EntityCollection();
179 | visualizer = new ConicSensorVisualizer(scene, entityCollection);
180 |
181 | var testObject = entityCollection.getOrCreateEntity('test');
182 | testObject.addProperty('conicSensor');
183 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
184 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
185 |
186 | var testObject2 = entityCollection.getOrCreateEntity('test2');
187 | testObject2.addProperty('conicSensor');
188 | testObject2.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
189 | testObject2.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
190 |
191 | var conicSensor = new ConicSensorGraphics();
192 | conicSensor.intersectionColor = new ConstantProperty(new Color(0.1, 0.2, 0.3, 0.4));
193 | testObject.conicSensor = conicSensor;
194 |
195 | var conicSensor2 = new ConicSensorGraphics();
196 | conicSensor2.intersectionColor = new ConstantProperty(new Color(0.4, 0.3, 0.2, 0.1));
197 | testObject2.conicSensor = conicSensor2;
198 |
199 | visualizer.update(time);
200 |
201 | expect(scene.primitives.length).toEqual(2);
202 | var c = scene.primitives.get(0);
203 | expect(c.intersectionColor).toEqual(testObject.conicSensor.intersectionColor.getValue(time));
204 |
205 | c = scene.primitives.get(1);
206 | expect(c.intersectionColor).toEqual(testObject2.conicSensor.intersectionColor.getValue(time));
207 | });
208 |
209 | it('should create a ComplexConicSensor with CZML defaults from an empty conicSensor', function() {
210 | var time = JulianDate.now();
211 | var entityCollection = new EntityCollection();
212 | visualizer = new ConicSensorVisualizer(scene, entityCollection);
213 |
214 | var testObject = entityCollection.getOrCreateEntity('test');
215 | testObject.addProperty('conicSensor');
216 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
217 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
218 |
219 | testObject.conicSensor = new ConicSensorGraphics();
220 | visualizer.update(time);
221 |
222 | expect(scene.primitives.length).toEqual(1);
223 | var c = scene.primitives.get(0);
224 | expect(c.directions.length).toBeGreaterThan(0);
225 | expect(isFinite(c.radius)).toEqual(false);
226 | expect(c.show).toEqual(true);
227 | });
228 |
229 | it('should remove primitives', function() {
230 | var entityCollection = new EntityCollection();
231 | visualizer = new ConicSensorVisualizer(scene, entityCollection);
232 |
233 | var testObject = entityCollection.getOrCreateEntity('test');
234 | testObject.addProperty('conicSensor');
235 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
236 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
237 | var conicSensor = new ConicSensorGraphics();
238 | conicSensor.maximumClockAngle = new ConstantProperty(1);
239 | conicSensor.outerHalfAngle = new ConstantProperty(1);
240 | testObject.conicSensor = conicSensor;
241 |
242 | var time = JulianDate.now();
243 | expect(scene.primitives.length).toEqual(0);
244 | visualizer.update(time);
245 | expect(scene.primitives.length).toEqual(1);
246 | expect(scene.primitives.get(0).show).toEqual(true);
247 | entityCollection.removeAll();
248 | visualizer.update(time);
249 | expect(scene.primitives.length).toEqual(0);
250 | });
251 |
252 | it('should set entity property', function() {
253 | var entityCollection = new EntityCollection();
254 | visualizer = new ConicSensorVisualizer(scene, entityCollection);
255 |
256 | var testObject = entityCollection.getOrCreateEntity('test');
257 | testObject.addProperty('conicSensor');
258 | testObject.position = new ConstantProperty(new Cartesian3(1234, 5678, 9101112));
259 | testObject.orientation = new ConstantProperty(new Quaternion(0, 0, 0, 1));
260 | var conicSensor = new ConicSensorGraphics();
261 | conicSensor.maximumClockAngle = new ConstantProperty(1);
262 | conicSensor.outerHalfAngle = new ConstantProperty(1);
263 | testObject.conicSensor = conicSensor;
264 |
265 | var time = JulianDate.now();
266 | visualizer.update(time);
267 | expect(scene.primitives.get(0).id).toEqual(testObject);
268 | });
269 | });
270 | });
271 |
--------------------------------------------------------------------------------
/lib/custom/custom-sensor-volume.js:
--------------------------------------------------------------------------------
1 | define(function(require) {
2 | 'use strict';
3 |
4 | var BoundingSphere = require('Cesium/Core/BoundingSphere');
5 | var Cartesian3 = require('Cesium/Core/Cartesian3');
6 | var Color = require('Cesium/Core/Color');
7 | var combine = require('Cesium/Core/combine');
8 | var ComponentDatatype = require('Cesium/Core/ComponentDatatype');
9 | var defaultValue = require('Cesium/Core/defaultValue');
10 | var defined = require('Cesium/Core/defined');
11 | var defineProperties = require('Cesium/Core/defineProperties');
12 | var destroyObject = require('Cesium/Core/destroyObject');
13 | var DeveloperError = require('Cesium/Core/DeveloperError');
14 | var Matrix4 = require('Cesium/Core/Matrix4');
15 | var PrimitiveType = require('Cesium/Core/PrimitiveType');
16 | var Buffer = require('Cesium/Renderer/Buffer');
17 | var BufferUsage = require('Cesium/Renderer/BufferUsage');
18 | var DrawCommand = require('Cesium/Renderer/DrawCommand');
19 | var Pass = require('Cesium/Renderer/Pass');
20 | var RenderState = require('Cesium/Renderer/RenderState');
21 | var ShaderProgram = require('Cesium/Renderer/ShaderProgram');
22 | var ShaderSource = require('Cesium/Renderer/ShaderSource');
23 | var VertexArray = require('Cesium/Renderer/VertexArray');
24 | var BlendingState = require('Cesium/Scene/BlendingState');
25 | var CullFace = require('Cesium/Scene/CullFace');
26 | var Material = require('Cesium/Scene/Material');
27 | var SceneMode = require('Cesium/Scene/SceneMode');
28 |
29 | var CustomSensorVolumeFS = require('text!./custom-sensor-volume-fs.glsl');
30 | var CustomSensorVolumeVS = require('text!./custom-sensor-volume-vs.glsl');
31 | var SensorVolume = require('text!../sensor-volume.glsl');
32 |
33 | var attributeLocations = {
34 | position: 0,
35 | normal: 1
36 | };
37 |
38 | var FAR = 5906376272000.0; // distance from the Sun to Pluto in meters.
39 |
40 | /**
41 | * DOC_TBA
42 | *
43 | * @alias CustomSensorVolume
44 | * @constructor
45 | */
46 | var CustomSensorVolume = function(options) {
47 | options = defaultValue(options, defaultValue.EMPTY_OBJECT);
48 |
49 | this._pickId = undefined;
50 | this._pickPrimitive = defaultValue(options._pickPrimitive, this);
51 |
52 | this._frontFaceColorCommand = new DrawCommand();
53 | this._backFaceColorCommand = new DrawCommand();
54 | this._pickCommand = new DrawCommand();
55 |
56 | this._boundingSphere = new BoundingSphere();
57 | this._boundingSphereWC = new BoundingSphere();
58 |
59 | this._frontFaceColorCommand.primitiveType = PrimitiveType.TRIANGLES;
60 | this._frontFaceColorCommand.boundingVolume = this._boundingSphereWC;
61 | this._frontFaceColorCommand.owner = this;
62 |
63 | this._backFaceColorCommand.primitiveType = this._frontFaceColorCommand.primitiveType;
64 | this._backFaceColorCommand.boundingVolume = this._frontFaceColorCommand.boundingVolume;
65 | this._backFaceColorCommand.owner = this;
66 |
67 | this._pickCommand.primitiveType = this._frontFaceColorCommand.primitiveType;
68 | this._pickCommand.boundingVolume = this._frontFaceColorCommand.boundingVolume;
69 | this._pickCommand.owner = this;
70 |
71 | /**
72 | * true if this sensor will be shown; otherwise, false
73 | *
74 | * @type {Boolean}
75 | * @default true
76 | */
77 | this.show = defaultValue(options.show, true);
78 |
79 | /**
80 | * When true, a polyline is shown where the sensor outline intersections the globe.
81 | *
82 | * @type {Boolean}
83 | *
84 | * @default true
85 | *
86 | * @see CustomSensorVolume#intersectionColor
87 | */
88 | this.showIntersection = defaultValue(options.showIntersection, true);
89 |
90 | /**
91 | *
92 | * Determines if a sensor intersecting the ellipsoid is drawn through the ellipsoid and potentially out
93 | * to the other side, or if the part of the sensor intersecting the ellipsoid stops at the ellipsoid.
94 | *
95 | *
96 | * @type {Boolean}
97 | * @default false
98 | */
99 | this.showThroughEllipsoid = defaultValue(options.showThroughEllipsoid, false);
100 | this._showThroughEllipsoid = this.showThroughEllipsoid;
101 |
102 | /**
103 | * The 4x4 transformation matrix that transforms this sensor from model to world coordinates. In it's model
104 | * coordinates, the sensor's principal direction is along the positive z-axis. The clock angle, sometimes
105 | * called azimuth, is the angle in the sensor's X-Y plane measured from the positive X-axis toward the positive
106 | * Y-axis. The cone angle, sometimes called elevation, is the angle out of the X-Y plane along the positive Z-axis.
107 | *
108 | *
109 | *
110 | * Model coordinate system for a custom sensor
111 | *
112 | *
113 | * @type {Matrix4}
114 | * @default {@link Matrix4.IDENTITY}
115 | *
116 | * @example
117 | * // The sensor's vertex is located on the surface at -75.59777 degrees longitude and 40.03883 degrees latitude.
118 | * // The sensor's opens upward, along the surface normal.
119 | * var center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
120 | * sensor.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
121 | */
122 | this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
123 | this._modelMatrix = new Matrix4();
124 |
125 | /**
126 | * DOC_TBA
127 | *
128 | * @type {Number}
129 | * @default {@link Number.POSITIVE_INFINITY}
130 | */
131 | this.radius = defaultValue(options.radius, Number.POSITIVE_INFINITY);
132 |
133 | this._directions = undefined;
134 | this._directionsDirty = false;
135 | this.directions = defined(options.directions) ? options.directions : [];
136 |
137 | /**
138 | * The surface appearance of the sensor. This can be one of several built-in {@link Material} objects or a custom material, scripted with
139 | * {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}.
140 | *
141 | * The default material is Material.ColorType.
142 | *
335 | * Do not call this function directly. This is documented just to
336 | * list the exceptions that may be propagated when the scene is rendered:
337 | *