27 |
28 |
29 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/cesium-sensor-volumes.js:
--------------------------------------------------------------------------------
1 | import initialize from './initialize';
2 | import ConicSensorGraphics from './conic/conic-sensor-graphics';
3 | import ConicSensorVisualizer from './conic/conic-sensor-visualizer';
4 | import CustomPatternSensorGraphics from './custom/custom-pattern-sensor-graphics';
5 | import CustomPatternSensorVisualizer from './custom/custom-pattern-sensor-visualizer';
6 | import CustomSensorVolume from './custom/custom-sensor-volume';
7 | import RectangularPyramidSensorVolume from './rectangular/rectangular-pyramid-sensor-volume';
8 | import RectangularSensorGraphics from './rectangular/rectangular-sensor-graphics';
9 | import RectangularSensorVisualizer from './rectangular/rectangular-sensor-visualizer';
10 |
11 | initialize();
12 |
13 | export default {
14 | ConicSensorGraphics,
15 | ConicSensorVisualizer,
16 | CustomPatternSensorGraphics,
17 | CustomPatternSensorVisualizer,
18 | CustomSensorVolume,
19 | RectangularPyramidSensorVolume,
20 | RectangularSensorGraphics,
21 | RectangularSensorVisualizer
22 | };
23 |
--------------------------------------------------------------------------------
/lib/copyright-header.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Cesium Sensor Volumes - https://github.com/Flowm/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/Flowm/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/sensor-volume.glsl:
--------------------------------------------------------------------------------
1 | #version 300 es
2 |
3 | uniform vec4 u_intersectionColor;
4 | uniform float u_intersectionWidth;
5 |
6 | bool inSensorShadow(vec3 coneVertexWC, vec3 pointWC)
7 | {
8 | // Diagonal matrix from the unscaled ellipsoid space to the scaled space.
9 | vec3 D = czm_ellipsoidInverseRadii;
10 |
11 | // Sensor vertex in the scaled ellipsoid space
12 | vec3 q = D * coneVertexWC;
13 | float qMagnitudeSquared = dot(q, q);
14 | float test = qMagnitudeSquared - 1.0;
15 |
16 | // Sensor vertex to fragment vector in the ellipsoid's scaled space
17 | vec3 temp = D * pointWC - q;
18 | float d = dot(temp, q);
19 |
20 | // Behind silhouette plane and inside silhouette cone
21 | return (d < -test) && (d / length(temp) < -sqrt(test));
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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.100.0",
4 | "description": "A Cesium plugin for visualizing sensor volumes.",
5 | "homepage": "https://github.com/Flowm/cesium-sensor-volumes",
6 | "license": "Apache-2.0",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/Flowm/cesium-sensor-volumes.git"
10 | },
11 | "keywords": [
12 | "cesium"
13 | ],
14 | "main": "dist/cesium-sensor-volumes.js",
15 | "module": "dist/cesium-sensor-volumes.es.js",
16 | "exports": {
17 | ".": {
18 | "import": "./dist/cesium-sensor-volumes.es.js",
19 | "require": "./dist/cesium-sensor-volumes.js"
20 | },
21 | "./engine": {
22 | "import": "./dist/cesium-sensor-volumes.engine.es.js"
23 | }
24 | },
25 | "dependencies": {
26 | "cesium": "^1.134"
27 | },
28 | "devDependencies": {
29 | "@rollup/plugin-terser": "^0.2.1",
30 | "browser-sync": "^2.27.12",
31 | "del": "^6.1.1",
32 | "electron": "23.1.1",
33 | "glsl-strip-comments": "^1.0.0",
34 | "gulp": "^4.0.2",
35 | "gulp-babel": "^8.0.0",
36 | "gulp-xo": "^0.15.0",
37 | "jasmine-core": "^4.5.0",
38 | "karma": "^6.4.1",
39 | "karma-chrome-launcher": "^3.1.1",
40 | "karma-coverage": "^2.2.0",
41 | "karma-electron-launcher": "^0.3.0",
42 | "karma-jasmine": "^5.1.0",
43 | "karma-requirejs": "^1.1.0",
44 | "rollup": "^3.8.1",
45 | "rollup-plugin-string": "^3.0.0",
46 | "through2": "^4.0.2"
47 | },
48 | "scripts": {
49 | "build": "gulp build",
50 | "start": "gulp serve",
51 | "lint": "gulp lint",
52 | "test": "gulp test",
53 | "ci": "gulp ci",
54 | "gulp": "gulp"
55 | },
56 | "xo": {
57 | "globals": [
58 | "define"
59 | ],
60 | "esnext": false,
61 | "rules": {
62 | "capitalized-comments": "off",
63 | "func-names": "off",
64 | "import/no-amd": "off",
65 | "import/no-extraneous-dependencies": "off",
66 | "import/no-unresolved": "off",
67 | "import/no-webpack-loader-syntax": "off",
68 | "object-curly-spacing": [
69 | "error",
70 | "always",
71 | {
72 | "objectsInObjects": false,
73 | "arraysInObjects": false
74 | }
75 | ],
76 | "space-before-function-paren": [
77 | "error",
78 | "never"
79 | ]
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [cesium](https://cesium.com/cesiumjs/)-sensor-volumes
2 | [](http://www.apache.org/licenses/LICENSE-2.0.html)
3 |
4 | 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.
5 |
6 | ## Install
7 |
8 | This version isn't installable from npm as it is a customized version.
9 |
10 | ## Usage
11 |
12 | Prebuilt minified and unminified versions of the plugin are in the [dist](dist/) directory.
13 |
14 | ### Using with the `cesium` package
15 |
16 | Include the `cesium-sensor-volumes.js` file using a `script` tag after the `Cesium.js` `script` tag.
17 |
18 | The plugin automatically adds support for the CZML properties `agi_conicSensor`, `agi_customPatternSensor`, and `agi_rectangularSensor`.
19 | 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.
22 | The CZML processing does this automatically.
23 |
24 | ```html
25 |
26 |
27 |
37 | ```
38 |
39 | ### Using with `@cesium/engine` for better tree-shaking
40 |
41 | For projects using `@cesium/engine` instead of the full `cesium` package, you can use the engine-specific builds for more efficient tree-shaking:
42 |
43 | **ES Module:**
44 | ```javascript
45 | import CesiumSensorVolumes from 'cesium-sensor-volumes/engine';
46 | // or directly:
47 | // import CesiumSensorVolumes from './dist/cesium-sensor-volumes.engine.es.js';
48 | ```
49 |
50 | The engine builds (`cesium-sensor-volumes.engine.es.js` and `cesium-sensor-volumes.engine.es.min.js`) import from `@cesium/engine` instead of `cesium`, allowing bundlers to better optimize your final bundle size.
51 |
52 | **Note:** When using the engine builds, make sure you have `@cesium/engine` installed in your project:
53 | ```bash
54 | npm install @cesium/engine
55 | ```
56 |
57 | ### Examples
58 |
59 | Simple examples are included in the [examples](examples/) folder.
60 | To run locally, run `npm start` and navigate to [http://localhost:3000](http://localhost:3000) and select the example application to run.
61 |
62 | ## Build
63 |
64 | To build, run `npm install`, then run `npm run build`.
65 |
66 | ## License
67 |
68 | Apache 2.0. Free for commercial and non-commercial use. See [LICENSE.md](LICENSE.md).
69 |
--------------------------------------------------------------------------------
/lib/custom/custom-sensor-volume-fs.glsl:
--------------------------------------------------------------------------------
1 | #version 300 es
2 |
3 | uniform bool u_showIntersection;
4 | uniform bool u_showThroughEllipsoid;
5 |
6 | uniform float u_sensorRadius;
7 | uniform float u_normalDirection;
8 |
9 | in vec3 v_positionWC;
10 | in vec3 v_positionEC;
11 | in vec3 v_normalEC;
12 |
13 | vec4 getColor(float sensorRadius, vec3 pointEC)
14 | {
15 | czm_materialInput materialInput;
16 |
17 | vec3 pointMC = (czm_inverseModelView * vec4(pointEC, 1.0)).xyz;
18 | materialInput.st = sensor2dTextureCoordinates(sensorRadius, pointMC);
19 | materialInput.str = pointMC / sensorRadius;
20 |
21 | vec3 positionToEyeEC = -v_positionEC;
22 | materialInput.positionToEyeEC = positionToEyeEC;
23 |
24 | vec3 normalEC = normalize(v_normalEC);
25 | materialInput.normalEC = u_normalDirection * normalEC;
26 |
27 | czm_material material = czm_getMaterial(materialInput);
28 | return mix(czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC), vec4(material.diffuse, material.alpha), 0.4);
29 | }
30 |
31 | bool isOnBoundary(float value, float epsilon)
32 | {
33 | float width = getIntersectionWidth();
34 | float tolerance = width * epsilon;
35 |
36 | float delta = max(abs(dFdx(value)), abs(dFdy(value)));
37 | float pixels = width * delta;
38 | float temp = abs(value);
39 | // There are a couple things going on here.
40 | // First we test the value at the current fragment to see if it is within the tolerance.
41 | // We also want to check if the value of an adjacent pixel is within the tolerance,
42 | // but we don't want to admit points that are obviously not on the surface.
43 | // For example, if we are looking for "value" to be close to 0, but value is 1 and the adjacent value is 2,
44 | // then the delta would be 1 and "temp - delta" would be "1 - 1" which is zero even though neither of
45 | // the points is close to zero.
46 | return temp < tolerance && temp < pixels || (delta < 10.0 * tolerance && temp - delta < tolerance && temp < pixels);
47 | }
48 |
49 | vec4 shade(bool isOnBoundary)
50 | {
51 | if (u_showIntersection && isOnBoundary)
52 | {
53 | return getIntersectionColor();
54 | }
55 | return getColor(u_sensorRadius, v_positionEC);
56 | }
57 |
58 | float ellipsoidSurfaceFunction(vec3 point)
59 | {
60 | vec3 scaled = czm_ellipsoidInverseRadii * point;
61 | return dot(scaled, scaled) - 1.0;
62 | }
63 |
64 | void main()
65 | {
66 | vec3 sensorVertexWC = czm_model[3].xyz; // (0.0, 0.0, 0.0) in model coordinates
67 | vec3 sensorVertexEC = czm_modelView[3].xyz; // (0.0, 0.0, 0.0) in model coordinates
68 |
69 | float ellipsoidValue = ellipsoidSurfaceFunction(v_positionWC);
70 |
71 | // Occluded by the ellipsoid?
72 | if (!u_showThroughEllipsoid)
73 | {
74 | // Discard if in the ellipsoid
75 | // PERFORMANCE_IDEA: A coarse check for ellipsoid intersection could be done on the CPU first.
76 | if (ellipsoidValue < 0.0)
77 | {
78 | discard;
79 | }
80 |
81 | // Discard if in the sensor's shadow
82 | if (inSensorShadow(sensorVertexWC, v_positionWC))
83 | {
84 | discard;
85 | }
86 | }
87 |
88 | // Discard if not in the sensor's sphere
89 | // PERFORMANCE_IDEA: We can omit this check if the radius is Number.POSITIVE_INFINITY.
90 | if (distance(v_positionEC, sensorVertexEC) > u_sensorRadius)
91 | {
92 | discard;
93 | }
94 |
95 | // Notes: Each surface functions should have an associated tolerance based on the floating point error.
96 | bool isOnEllipsoid = isOnBoundary(ellipsoidValue, czm_epsilon3);
97 | out_FragColor = shade(isOnEllipsoid);
98 | }
99 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/lib/rectangular/rectangular-pyramid-sensor-volume.js:
--------------------------------------------------------------------------------
1 | import {
2 | clone,
3 | defined,
4 | destroyObject,
5 | DeveloperError,
6 | Frozen,
7 | Math as CesiumMath,
8 | Spherical
9 | } from 'cesium';
10 | import CustomSensorVolume from '../custom/custom-sensor-volume';
11 |
12 | function assignSpherical(index, array, clock, cone) {
13 | var spherical = array[index];
14 | if (!defined(spherical)) {
15 | spherical = new Spherical();
16 | array[index] = spherical;
17 | }
18 | spherical.clock = clock;
19 | spherical.cone = cone;
20 | spherical.magnitude = 1.0;
21 | }
22 |
23 | function updateDirections(rectangularSensor) {
24 | var directions = rectangularSensor._customSensor.directions;
25 |
26 | // At 90 degrees the sensor is completely open, and tan() goes to infinity.
27 | var tanX = Math.tan(Math.min(rectangularSensor._xHalfAngle, CesiumMath.toRadians(89.0)));
28 | var tanY = Math.tan(Math.min(rectangularSensor._yHalfAngle, CesiumMath.toRadians(89.0)));
29 | var theta = Math.atan(tanX / tanY);
30 | var cone = Math.atan(Math.sqrt((tanX * tanX) + (tanY * tanY)));
31 |
32 | assignSpherical(0, directions, theta, cone);
33 | assignSpherical(1, directions, CesiumMath.toRadians(180.0) - theta, cone);
34 | assignSpherical(2, directions, CesiumMath.toRadians(180.0) + theta, cone);
35 | assignSpherical(3, directions, -theta, cone);
36 |
37 | directions.length = 4;
38 | rectangularSensor._customSensor.directions = directions;
39 | }
40 |
41 | const RectangularPyramidSensorVolume = function(options) {
42 | options = options ?? Frozen.EMPTY_OBJECT;
43 |
44 | var customSensorOptions = clone(options);
45 | customSensorOptions._pickPrimitive = options._pickPrimitive ?? this;
46 | customSensorOptions.directions = undefined;
47 | this._customSensor = new CustomSensorVolume(customSensorOptions);
48 |
49 | this._xHalfAngle = options.xHalfAngle ?? CesiumMath.PI_OVER_TWO;
50 | this._yHalfAngle = options.yHalfAngle ?? CesiumMath.PI_OVER_TWO;
51 |
52 | updateDirections(this);
53 | };
54 |
55 | Object.defineProperties(RectangularPyramidSensorVolume.prototype, {
56 | xHalfAngle: {
57 | get: function() {
58 | return this._xHalfAngle;
59 | },
60 | set: function(value) {
61 | // >>includeStart('debug', pragmas.debug)
62 | if (value > CesiumMath.PI_OVER_TWO) {
63 | throw new DeveloperError('xHalfAngle must be less than or equal to 90 degrees.');
64 | }
65 | // >>includeEnd('debug');
66 |
67 | if (this._xHalfAngle !== value) {
68 | this._xHalfAngle = value;
69 | updateDirections(this);
70 | }
71 | }
72 | },
73 | yHalfAngle: {
74 | get: function() {
75 | return this._yHalfAngle;
76 | },
77 | set: function(value) {
78 | // >>includeStart('debug', pragmas.debug)
79 | if (value > CesiumMath.PI_OVER_TWO) {
80 | throw new DeveloperError('yHalfAngle must be less than or equal to 90 degrees.');
81 | }
82 | // >>includeEnd('debug');
83 |
84 | if (this._yHalfAngle !== value) {
85 | this._yHalfAngle = value;
86 | updateDirections(this);
87 | }
88 | }
89 | },
90 | show: {
91 | get: function() {
92 | return this._customSensor.show;
93 | },
94 | set: function(value) {
95 | this._customSensor.show = value;
96 | }
97 | },
98 | showIntersection: {
99 | get: function() {
100 | return this._customSensor.showIntersection;
101 | },
102 | set: function(value) {
103 | this._customSensor.showIntersection = value;
104 | }
105 | },
106 | showThroughEllipsoid: {
107 | get: function() {
108 | return this._customSensor.showThroughEllipsoid;
109 | },
110 | set: function(value) {
111 | this._customSensor.showThroughEllipsoid = value;
112 | }
113 | },
114 | modelMatrix: {
115 | get: function() {
116 | return this._customSensor.modelMatrix;
117 | },
118 | set: function(value) {
119 | this._customSensor.modelMatrix = value;
120 | }
121 | },
122 | radius: {
123 | get: function() {
124 | return this._customSensor.radius;
125 | },
126 | set: function(value) {
127 | this._customSensor.radius = value;
128 | }
129 | },
130 | lateralSurfaceMaterial: {
131 | get: function() {
132 | return this._customSensor.lateralSurfaceMaterial;
133 | },
134 | set: function(value) {
135 | this._customSensor.lateralSurfaceMaterial = value;
136 | }
137 | },
138 | intersectionColor: {
139 | get: function() {
140 | return this._customSensor.intersectionColor;
141 | },
142 | set: function(value) {
143 | this._customSensor.intersectionColor = value;
144 | }
145 | },
146 | intersectionWidth: {
147 | get: function() {
148 | return this._customSensor.intersectionWidth;
149 | },
150 | set: function(value) {
151 | this._customSensor.intersectionWidth = value;
152 | }
153 | },
154 | id: {
155 | get: function() {
156 | return this._customSensor.id;
157 | },
158 | set: function(value) {
159 | this._customSensor.id = value;
160 | }
161 | }
162 | });
163 |
164 | RectangularPyramidSensorVolume.prototype.update = function(frameState) {
165 | this._customSensor.update(frameState);
166 | };
167 |
168 | RectangularPyramidSensorVolume.prototype.isDestroyed = function() {
169 | return false;
170 | };
171 |
172 | RectangularPyramidSensorVolume.prototype.destroy = function() {
173 | this._customSensor = this._customSensor && this._customSensor.destroy();
174 | return destroyObject(this);
175 | };
176 |
177 | export default RectangularPyramidSensorVolume;
178 |
--------------------------------------------------------------------------------
/lib/custom/custom-pattern-sensor-graphics.js:
--------------------------------------------------------------------------------
1 | import {
2 | defined,
3 | DeveloperError,
4 | Event,
5 | Frozen,
6 | createMaterialPropertyDescriptor,
7 | createPropertyDescriptor
8 | } from 'cesium';
9 |
10 | /**
11 | * An optionally time-dynamic custom patterned sensor.
12 | *
13 | * @alias CustomPatternSensorGraphics
14 | * @constructor
15 | */
16 | const CustomPatternSensorGraphics = function(options) {
17 | this._directions = undefined;
18 | this._directionsSubscription = undefined;
19 |
20 | this._lateralSurfaceMaterial = undefined;
21 | this._lateralSurfaceMaterialSubscription = undefined;
22 |
23 | this._intersectionColor = undefined;
24 | this._intersectionColorSubscription = undefined;
25 | this._intersectionWidth = undefined;
26 | this._intersectionWidthSubscription = undefined;
27 | this._showIntersection = undefined;
28 | this._showIntersectionSubscription = undefined;
29 | this._radius = undefined;
30 | this._radiusSubscription = undefined;
31 | this._show = undefined;
32 | this._showSubscription = undefined;
33 | this._definitionChanged = new Event();
34 |
35 | this.merge(options ?? Frozen.EMPTY_OBJECT);
36 | };
37 |
38 | Object.defineProperties(CustomPatternSensorGraphics.prototype, {
39 | /**
40 | * Gets the event that is raised whenever a new property is assigned.
41 | * @memberof CustomPatternSensorGraphics.prototype
42 | *
43 | * @type {Event}
44 | * @readonly
45 | */
46 | definitionChanged: {
47 | get: function() {
48 | return this._definitionChanged;
49 | }
50 | },
51 |
52 | /**
53 | * A {@link Property} which returns an array of {@link Spherical} instances representing the sensor's projection.
54 | * @memberof CustomPatternSensorGraphics.prototype
55 | * @type {Property}
56 | */
57 | directions: createPropertyDescriptor('directions'),
58 |
59 | /**
60 | * Gets or sets the {@link MaterialProperty} specifying the the sensor's appearance.
61 | * @memberof CustomPatternSensorGraphics.prototype
62 | * @type {MaterialProperty}
63 | */
64 | lateralSurfaceMaterial: createMaterialPropertyDescriptor('lateralSurfaceMaterial'),
65 |
66 | /**
67 | * 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.
68 | * @memberof CustomPatternSensorGraphics.prototype
69 | * @type {Property}
70 | */
71 | intersectionColor: createPropertyDescriptor('intersectionColor'),
72 |
73 | /**
74 | * Gets or sets the numeric {@link Property} specifying the width of the line formed by the intersection of the sensor and other central bodies.
75 | * @memberof CustomPatternSensorGraphics.prototype
76 | * @type {Property}
77 | */
78 | intersectionWidth: createPropertyDescriptor('intersectionWidth'),
79 |
80 | /**
81 | * Gets or sets the boolean {@link Property} specifying the visibility of the line formed by the intersection of the sensor and other central bodies.
82 | * @memberof CustomPatternSensorGraphics.prototype
83 | * @type {Property}
84 | */
85 | showIntersection: createPropertyDescriptor('showIntersection'),
86 |
87 | /**
88 | * Gets or sets the numeric {@link Property} specifying the radius of the sensor's projection.
89 | * @memberof CustomPatternSensorGraphics.prototype
90 | * @type {Property}
91 | */
92 | radius: createPropertyDescriptor('radius'),
93 |
94 | /**
95 | * Gets or sets the boolean {@link Property} specifying the visibility of the sensor.
96 | * @memberof CustomPatternSensorGraphics.prototype
97 | * @type {Property}
98 | */
99 | show: createPropertyDescriptor('show')
100 | });
101 |
102 | /**
103 | * Duplicates a CustomPatternSensorGraphics instance.
104 | *
105 | * @param {CustomPatternSensorGraphics} [result] The object onto which to store the result.
106 | * @returns {CustomPatternSensorGraphics} The modified result parameter or a new instance if one was not provided.
107 | */
108 | CustomPatternSensorGraphics.prototype.clone = function(result) {
109 | if (!defined(result)) {
110 | result = new CustomPatternSensorGraphics();
111 | }
112 | result.directions = this.directions;
113 | result.radius = this.radius;
114 | result.show = this.show;
115 | result.showIntersection = this.showIntersection;
116 | result.intersectionColor = this.intersectionColor;
117 | result.intersectionWidth = this.intersectionWidth;
118 | result.lateralSurfaceMaterial = this.lateralSurfaceMaterial;
119 | return result;
120 | };
121 |
122 | /**
123 | * Assigns each unassigned property on this object to the value
124 | * of the same property on the provided source object.
125 | *
126 | * @param {CustomPatternSensorGraphics} source The object to be merged into this object.
127 | */
128 | CustomPatternSensorGraphics.prototype.merge = function(source) {
129 | // >>includeStart('debug', pragmas.debug);
130 | if (!defined(source)) {
131 | throw new DeveloperError('source is required.');
132 | }
133 | // >>includeEnd('debug');
134 |
135 | this.directions = this.directions ?? source.directions;
136 | this.radius = this.radius ?? source.radius;
137 | this.show = this.show ?? source.show;
138 | this.showIntersection = this.showIntersection ?? source.showIntersection;
139 | this.intersectionColor = this.intersectionColor ?? source.intersectionColor;
140 | this.intersectionWidth = this.intersectionWidth ?? source.intersectionWidth;
141 | this.lateralSurfaceMaterial = this.lateralSurfaceMaterial ?? source.lateralSurfaceMaterial;
142 | };
143 |
144 | export default CustomPatternSensorGraphics;
145 |
--------------------------------------------------------------------------------
/lib/rectangular/rectangular-sensor-graphics.js:
--------------------------------------------------------------------------------
1 | import {
2 | defined,
3 | DeveloperError,
4 | Event,
5 | createPropertyDescriptor
6 | } from 'cesium';
7 |
8 | /**
9 | * An optionally time-dynamic pyramid.
10 | *
11 | * @alias RectangularSensorGraphics
12 | * @constructor
13 | */
14 | const RectangularSensorGraphics = function() {
15 | this._xHalfAngle = undefined;
16 | this._xHalfAngleSubscription = undefined;
17 | this._yHalfAngle = undefined;
18 | this._yHalfAngleSubscription = undefined;
19 |
20 | this._lateralSurfaceMaterial = undefined;
21 | this._lateralSurfaceMaterialSubscription = undefined;
22 |
23 | this._intersectionColor = undefined;
24 | this._intersectionColorSubscription = undefined;
25 | this._intersectionWidth = undefined;
26 | this._intersectionWidthSubscription = undefined;
27 | this._showIntersection = undefined;
28 | this._showIntersectionSubscription = undefined;
29 | this._radius = undefined;
30 | this._radiusSubscription = undefined;
31 | this._show = undefined;
32 | this._showSubscription = undefined;
33 | this._definitionChanged = new Event();
34 | };
35 |
36 | Object.defineProperties(RectangularSensorGraphics.prototype, {
37 | /**
38 | * Gets the event that is raised whenever a new property is assigned.
39 | * @memberof RectangularSensorGraphics.prototype
40 | *
41 | * @type {Event}
42 | * @readonly
43 | */
44 | definitionChanged: {
45 | get: function() {
46 | return this._definitionChanged;
47 | }
48 | },
49 |
50 | /**
51 | * A {@link Property} which returns an array of {@link Spherical} instances representing the pyramid's projection.
52 | * @memberof RectangularSensorGraphics.prototype
53 | * @type {Property}
54 | */
55 | xHalfAngle: createPropertyDescriptor('xHalfAngle'),
56 |
57 | /**
58 | * A {@link Property} which returns an array of {@link Spherical} instances representing the pyramid's projection.
59 | * @memberof RectangularSensorGraphics.prototype
60 | * @type {Property}
61 | */
62 | yHalfAngle: createPropertyDescriptor('yHalfAngle'),
63 |
64 | /**
65 | * Gets or sets the {@link MaterialProperty} specifying the the pyramid's appearance.
66 | * @memberof RectangularSensorGraphics.prototype
67 | * @type {MaterialProperty}
68 | */
69 | lateralSurfaceMaterial: createPropertyDescriptor('lateralSurfaceMaterial'),
70 |
71 | /**
72 | * 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.
73 | * @memberof RectangularSensorGraphics.prototype
74 | * @type {Property}
75 | */
76 | intersectionColor: createPropertyDescriptor('intersectionColor'),
77 |
78 | /**
79 | * Gets or sets the numeric {@link Property} specifying the width of the line formed by the intersection of the pyramid and other central bodies.
80 | * @memberof RectangularSensorGraphics.prototype
81 | * @type {Property}
82 | */
83 | intersectionWidth: createPropertyDescriptor('intersectionWidth'),
84 |
85 | /**
86 | * Gets or sets the boolean {@link Property} specifying the visibility of the line formed by the intersection of the pyramid and other central bodies.
87 | * @memberof RectangularSensorGraphics.prototype
88 | * @type {Property}
89 | */
90 | showIntersection: createPropertyDescriptor('showIntersection'),
91 |
92 | /**
93 | * Gets or sets the numeric {@link Property} specifying the radius of the pyramid's projection.
94 | * @memberof RectangularSensorGraphics.prototype
95 | * @type {Property}
96 | */
97 | radius: createPropertyDescriptor('radius'),
98 |
99 | /**
100 | * Gets or sets the boolean {@link Property} specifying the visibility of the pyramid.
101 | * @memberof RectangularSensorGraphics.prototype
102 | * @type {Property}
103 | */
104 | show: createPropertyDescriptor('show')
105 | });
106 |
107 | /**
108 | * Duplicates a RectangularSensorGraphics instance.
109 | *
110 | * @param {RectangularSensorGraphics} [result] The object onto which to store the result.
111 | * @returns {RectangularSensorGraphics} The modified result parameter or a new instance if one was not provided.
112 | */
113 | RectangularSensorGraphics.prototype.clone = function(result) {
114 | if (!defined(result)) {
115 | result = new RectangularSensorGraphics();
116 | }
117 | result.xHalfAngle = this.xHalfAngle;
118 | result.yHalfAngle = this.yHalfAngle;
119 | result.radius = this.radius;
120 | result.show = this.show;
121 | result.showIntersection = this.showIntersection;
122 | result.intersectionColor = this.intersectionColor;
123 | result.intersectionWidth = this.intersectionWidth;
124 | result.lateralSurfaceMaterial = this.lateralSurfaceMaterial;
125 | return result;
126 | };
127 |
128 | /**
129 | * Assigns each unassigned property on this object to the value
130 | * of the same property on the provided source object.
131 | *
132 | * @param {RectangularSensorGraphics} source The object to be merged into this object.
133 | */
134 | RectangularSensorGraphics.prototype.merge = function(source) {
135 | // >>includeStart('debug', pragmas.debug);
136 | if (!defined(source)) {
137 | throw new DeveloperError('source is required.');
138 | }
139 | // >>includeEnd('debug');
140 |
141 | this.xHalfAngle = this.xHalfAngle ?? source.xHalfAngle;
142 | this.yHalfAngle = this.yHalfAngle ?? source.yHalfAngle;
143 | this.radius = this.radius ?? source.radius;
144 | this.show = this.show ?? source.show;
145 | this.showIntersection = this.showIntersection ?? source.showIntersection;
146 | this.intersectionColor = this.intersectionColor ?? source.intersectionColor;
147 | this.intersectionWidth = this.intersectionWidth ?? source.intersectionWidth;
148 | this.lateralSurfaceMaterial = this.lateralSurfaceMaterial ?? source.lateralSurfaceMaterial;
149 | };
150 |
151 | export default RectangularSensorGraphics;
152 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var path = require('path');
5 |
6 | var gulp = require('gulp');
7 | var through = require('through2');
8 | var del = require('del');
9 | var xo = require('gulp-xo');
10 |
11 | var rollup = require('rollup');
12 | var { string } = require('rollup-plugin-string');
13 | var terser = require('@rollup/plugin-terser');
14 | var glslStripComments = require('glsl-strip-comments');
15 |
16 | var browserSync = require('browser-sync').create();
17 |
18 | var reload = browserSync.reload;
19 |
20 | function runLint(src) {
21 | return gulp.src(src)
22 | .pipe(xo());
23 | }
24 | function lint() {
25 | return runLint(['lib/**/*.js', 'gulp/**/*.js', 'gulpfile.js']);
26 | }
27 | exports.lint = lint;
28 |
29 | function clean() {
30 | return del(['coverage', '.tmp', 'dist']);
31 | }
32 | exports.clean = clean;
33 |
34 | function preprocessShaders() {
35 | return gulp.src('lib/**/*.glsl')
36 | .pipe(through.obj(function(file, _, cb) {
37 | if (file.isBuffer()) {
38 | const output = glslStripComments(file.contents.toString(), { version: '300 es' });
39 | file.contents = Buffer.from(output);
40 | }
41 | cb(null, file);
42 | }))
43 | .pipe(gulp.dest('.tmp'));
44 | }
45 |
46 | function preprocessJs() {
47 | return gulp.src(['lib/**/*.js'])
48 | .pipe(gulp.dest('.tmp'));
49 | }
50 |
51 | function getCopyrightHeaders() {
52 | return fs.readFileSync('lib/copyright-header.js').toString();
53 | }
54 |
55 | async function buildEs() {
56 | const bundle = await rollup.rollup({
57 | input: '.tmp/cesium-sensor-volumes.js',
58 | plugins: [
59 | string({
60 | include: '**/*.glsl'
61 | })
62 | ],
63 | external: id => id === 'cesium' || /Cesium/.test(id)
64 | });
65 |
66 | await bundle.write({
67 | file: 'dist/cesium-sensor-volumes.es.js',
68 | format: 'es',
69 | banner: getCopyrightHeaders()
70 | });
71 | await bundle.write({
72 | file: 'dist/cesium-sensor-volumes.es.min.js',
73 | format: 'es',
74 | plugins: [terser({
75 | format: {
76 | comments: function(node, comment) {
77 | if (comment.type === 'comment2') {
78 | return /Copyright/i.test(comment.value);
79 | }
80 | }
81 | }
82 | })],
83 | banner: getCopyrightHeaders()
84 | });
85 | }
86 |
87 | function createEngineBuilds() {
88 | return gulp.src(['dist/cesium-sensor-volumes.es.js', 'dist/cesium-sensor-volumes.es.min.js'])
89 | .pipe(through.obj(function(file, _, cb) {
90 | if (file.isBuffer()) {
91 | var content = file.contents.toString();
92 | // Replace 'cesium' imports with '@cesium/engine'
93 | content = content.replace(/from ['"]cesium['"]/g, "from '@cesium/engine'");
94 | content = content.replace(/from"cesium"/g, 'from"@cesium/engine"');
95 | file.contents = Buffer.from(content);
96 | }
97 | // Rename the file to add .engine
98 | var basename = file.basename.replace('.es.js', '.engine.es.js').replace('.es.min.js', '.engine.es.min.js');
99 | file.basename = basename;
100 | cb(null, file);
101 | }))
102 | .pipe(gulp.dest('dist'));
103 | }
104 |
105 | exports.buildEs = gulp.series(clean, gulp.parallel(preprocessShaders, preprocessJs), buildEs);
106 |
107 | function generateShims() {
108 | // Search for Cesium modules and add shim modules that pull from the Cesium global
109 | return gulp.src(['./dist/cesium-sensor-volumes.es.js'])
110 | .pipe(through.obj(function(file, _, cb) {
111 | if (file.isBuffer()) {
112 | // Handle destructured imports from 'cesium'
113 | var cesiumDestructuredRegex = /import\s*\{\s*([^}]+)\s*\}\s*from\s*['"]cesium['"];?/g;
114 | var content = file.contents.toString();
115 |
116 | // Replace destructured imports with Cesium global references
117 | const output = content.replace(cesiumDestructuredRegex, (match, imports) => {
118 | // Parse the imports, handling aliases like "Math as CesiumMath"
119 | const importList = imports.split(',').map(imp => {
120 | const trimmed = imp.trim();
121 | if (trimmed.includes(' as ')) {
122 | const [cesiumName, localName] = trimmed.split(' as ').map(s => s.trim());
123 | return `const ${localName} = Cesium.${cesiumName};`;
124 | } else {
125 | return `const ${trimmed} = Cesium.${trimmed};`;
126 | }
127 | });
128 | return importList.join('\n');
129 | });
130 | file.contents = Buffer.from(output);
131 | }
132 | cb(null, file);
133 | }))
134 | .pipe(gulp.dest('.tmp/shimmed'));
135 | }
136 |
137 | async function buildUmd() {
138 | const bundle = await rollup.rollup({
139 | input: '.tmp/shimmed/cesium-sensor-volumes.es.js'
140 | });
141 | await bundle.write({
142 | file: 'dist/cesium-sensor-volumes.js',
143 | name: 'CesiumSensorVolumes',
144 | format: 'umd'
145 | });
146 | await bundle.write({
147 | file: 'dist/cesium-sensor-volumes.min.js',
148 | name: 'CesiumSensorVolumes',
149 | plugins: [terser({
150 | format: {
151 | comments: function(node, comment) {
152 | if (comment.type === 'comment2') {
153 | return /Copyright/i.test(comment.value);
154 | }
155 | }
156 | }
157 | })],
158 | format: 'umd'
159 | });
160 | }
161 | exports.build = gulp.series(exports.buildEs, createEngineBuilds, generateShims, buildUmd);
162 |
163 | exports.buildReload = gulp.series(exports.build, reload);
164 |
165 | function run(cb) {
166 | browserSync.init({
167 | server: '.'
168 | }, cb);
169 | }
170 |
171 | function watch(cb) {
172 | gulp.watch(['examples/**/*.html', 'examples/**/*.czml'], reload);
173 | gulp.watch(['lib/**/*.glsl'], exports.buildReload);
174 | gulp.watch(['lib/**/*.js'], exports.buildReload);
175 | cb();
176 | }
177 | exports.serve = gulp.series(exports.build, run, watch);
178 |
179 | function lintTest() {
180 | return runLint(['test/**/*.js']);
181 | }
182 |
183 | function test(done, options) {
184 | var Server = require('karma').Server;
185 |
186 | var server = new Server(Object.assign({
187 | configFile: path.join(__dirname, '/test/karma.conf.js'),
188 | singleRun: true
189 | }, options), done);
190 |
191 | server.start();
192 | }
193 | exports.test = gulp.series(lintTest, test);
194 |
195 | function testCI(done) {
196 | test(done, {
197 | browsers: ['Electron'],
198 | client: {
199 | args: [true]
200 | }
201 | });
202 | }
203 | exports.testCI = gulp.series(lintTest, testCI);
204 | exports.ci = gulp.series(lint, testCI, exports.build);
--------------------------------------------------------------------------------
/lib/conic/conic-sensor-graphics.js:
--------------------------------------------------------------------------------
1 | import {
2 | defined,
3 | DeveloperError,
4 | Event,
5 | Frozen,
6 | createMaterialPropertyDescriptor,
7 | createPropertyDescriptor
8 | } from 'cesium';
9 |
10 | /**
11 | * An optionally time-dynamic cone.
12 | *
13 | * @alias ConicSensorGraphics
14 | * @constructor
15 | */
16 | const ConicSensorGraphics = function(options) {
17 | this._minimumClockAngle = undefined;
18 | this._minimumClockAngleSubscription = undefined;
19 | this._maximumClockAngle = undefined;
20 | this._maximumClockAngleSubscription = undefined;
21 | this._innerHalfAngle = undefined;
22 | this._innerHalfAngleSubscription = undefined;
23 | this._outerHalfAngle = undefined;
24 | this._outerHalfAngleSubscription = undefined;
25 | this._lateralSurfaceMaterial = undefined;
26 | this._lateralSurfaceMaterialSubscription = undefined;
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 | this.merge(options ?? Frozen.EMPTY_OBJECT);
40 | };
41 |
42 | Object.defineProperties(ConicSensorGraphics.prototype, {
43 | /**
44 | * Gets the event that is raised whenever a new property is assigned.
45 | * @memberof ConicSensorGraphics.prototype
46 | *
47 | * @type {Event}
48 | * @readonly
49 | */
50 | definitionChanged: {
51 | get: function() {
52 | return this._definitionChanged;
53 | }
54 | },
55 |
56 | /**
57 | * Gets or sets the numeric {@link Property} specifying the the cone's minimum clock angle.
58 | * @memberof ConicSensorGraphics.prototype
59 | * @type {Property}
60 | */
61 | minimumClockAngle: createPropertyDescriptor('minimumClockAngle'),
62 |
63 | /**
64 | * Gets or sets the numeric {@link Property} specifying the the cone's maximum clock angle.
65 | * @memberof ConicSensorGraphics.prototype
66 | * @type {Property}
67 | */
68 | maximumClockAngle: createPropertyDescriptor('maximumClockAngle'),
69 |
70 | /**
71 | * Gets or sets the numeric {@link Property} specifying the the cone's inner half-angle.
72 | * @memberof ConicSensorGraphics.prototype
73 | * @type {Property}
74 | */
75 | innerHalfAngle: createPropertyDescriptor('innerHalfAngle'),
76 |
77 | /**
78 | * Gets or sets the numeric {@link Property} specifying the the cone's outer half-angle.
79 | * @memberof ConicSensorGraphics.prototype
80 | * @type {Property}
81 | */
82 | outerHalfAngle: createPropertyDescriptor('outerHalfAngle'),
83 |
84 | /**
85 | * Gets or sets the {@link MaterialProperty} specifying the the cone's appearance.
86 | * @memberof ConicSensorGraphics.prototype
87 | * @type {MaterialProperty}
88 | */
89 | lateralSurfaceMaterial: createMaterialPropertyDescriptor('lateralSurfaceMaterial'),
90 |
91 | /**
92 | * 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.
93 | * @memberof ConicSensorGraphics.prototype
94 | * @type {Property}
95 | */
96 | intersectionColor: createPropertyDescriptor('intersectionColor'),
97 |
98 | /**
99 | * Gets or sets the numeric {@link Property} specifying the width of the line formed by the intersection of the cone and other central bodies.
100 | * @memberof ConicSensorGraphics.prototype
101 | * @type {Property}
102 | */
103 | intersectionWidth: createPropertyDescriptor('intersectionWidth'),
104 |
105 | /**
106 | * Gets or sets the boolean {@link Property} specifying the visibility of the line formed by the intersection of the cone and other central bodies.
107 | * @memberof ConicSensorGraphics.prototype
108 | * @type {Property}
109 | */
110 | showIntersection: createPropertyDescriptor('showIntersection'),
111 |
112 | /**
113 | * Gets or sets the numeric {@link Property} specifying the radius of the cone's projection.
114 | * @memberof ConicSensorGraphics.prototype
115 | * @type {Property}
116 | */
117 | radius: createPropertyDescriptor('radius'),
118 |
119 | /**
120 | * Gets or sets the boolean {@link Property} specifying the visibility of the cone.
121 | * @memberof ConicSensorGraphics.prototype
122 | * @type {Property}
123 | */
124 | show: createPropertyDescriptor('show')
125 | });
126 |
127 | /**
128 | * Duplicates a ConicSensorGraphics instance.
129 | *
130 | * @param {ConicSensorGraphics} [result] The object onto which to store the result.
131 | * @returns {ConicSensorGraphics} The modified result parameter or a new instance if one was not provided.
132 | */
133 | ConicSensorGraphics.prototype.clone = function(result) {
134 | if (!defined(result)) {
135 | result = new ConicSensorGraphics();
136 | }
137 | result.show = this.show;
138 | result.innerHalfAngle = this.innerHalfAngle;
139 | result.outerHalfAngle = this.outerHalfAngle;
140 | result.minimumClockAngle = this.minimumClockAngle;
141 | result.maximumClockAngle = this.maximumClockAngle;
142 | result.radius = this.radius;
143 | result.showIntersection = this.showIntersection;
144 | result.intersectionColor = this.intersectionColor;
145 | result.intersectionWidth = this.intersectionWidth;
146 | result.lateralSurfaceMaterial = this.lateralSurfaceMaterial;
147 | return result;
148 | };
149 |
150 | /**
151 | * Assigns each unassigned property on this object to the value
152 | * of the same property on the provided source object.
153 | *
154 | * @param {ConicSensorGraphics} source The object to be merged into this object.
155 | */
156 | ConicSensorGraphics.prototype.merge = function(source) {
157 | // >>includeStart('debug', pragmas.debug);
158 | if (!defined(source)) {
159 | throw new DeveloperError('source is required.');
160 | }
161 | // >>includeEnd('debug');
162 |
163 | this.show = this.show ?? source.show;
164 | this.innerHalfAngle = this.innerHalfAngle ?? source.innerHalfAngle;
165 | this.outerHalfAngle = this.outerHalfAngle ?? source.outerHalfAngle;
166 | this.minimumClockAngle = this.minimumClockAngle ?? source.minimumClockAngle;
167 | this.maximumClockAngle = this.maximumClockAngle ?? source.maximumClockAngle;
168 | this.radius = this.radius ?? source.radius;
169 | this.showIntersection = this.showIntersection ?? source.showIntersection;
170 | this.intersectionColor = this.intersectionColor ?? source.intersectionColor;
171 | this.intersectionWidth = this.intersectionWidth ?? source.intersectionWidth;
172 | this.lateralSurfaceMaterial = this.lateralSurfaceMaterial ?? source.lateralSurfaceMaterial;
173 | };
174 |
175 | export default ConicSensorGraphics;
176 |
--------------------------------------------------------------------------------
/lib/custom/custom-pattern-sensor-visualizer.js:
--------------------------------------------------------------------------------
1 | import {
2 | AssociativeArray,
3 | Cartesian3,
4 | Color,
5 | defined,
6 | destroyObject,
7 | DeveloperError,
8 | Matrix3,
9 | Matrix4,
10 | Quaternion,
11 | MaterialProperty,
12 | Property
13 | } from 'cesium';
14 | import CustomSensorVolume from '../custom/custom-sensor-volume';
15 | import removePrimitive from '../util/remove-primitive';
16 |
17 | const defaultIntersectionColor = Color.WHITE;
18 | const defaultIntersectionWidth = 1.0;
19 | const defaultRadius = Number.POSITIVE_INFINITY;
20 |
21 | const matrix3Scratch = new Matrix3();
22 | const cachedPosition = new Cartesian3();
23 | const cachedOrientation = new Quaternion();
24 |
25 | /**
26 | * A {@link Visualizer} which maps {@link Entity#customPatternSensor} to a {@link CustomPatternSensor}.
27 | * @alias CustomPatternSensorVisualizer
28 | * @constructor
29 | *
30 | * @param {Scene} scene The scene the primitives will be rendered in.
31 | * @param {EntityCollection} entityCollection The entityCollection to visualize.
32 | */
33 | const CustomPatternSensorVisualizer = function(scene, entityCollection) {
34 | // >>includeStart('debug', pragmas.debug);
35 | if (!defined(scene)) {
36 | throw new DeveloperError('scene is required.');
37 | }
38 | if (!defined(entityCollection)) {
39 | throw new DeveloperError('entityCollection is required.');
40 | }
41 | // >>includeEnd('debug');
42 |
43 | entityCollection.collectionChanged.addEventListener(CustomPatternSensorVisualizer.prototype._onCollectionChanged, this);
44 |
45 | this._scene = scene;
46 | this._primitives = scene.primitives;
47 | this._entityCollection = entityCollection;
48 | this._hash = {};
49 | this._entitiesToVisualize = new AssociativeArray();
50 |
51 | this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
52 | };
53 |
54 | /**
55 | * Updates the primitives created by this visualizer to match their
56 | * Entity counterpart at the given time.
57 | *
58 | * @param {JulianDate} time The time to update to.
59 | * @returns {Boolean} This function always returns true.
60 | */
61 | CustomPatternSensorVisualizer.prototype.update = function(time) {
62 | // >>includeStart('debug', pragmas.debug);
63 | if (!defined(time)) {
64 | throw new DeveloperError('time is required.');
65 | }
66 | // >>includeEnd('debug');
67 |
68 | var entities = this._entitiesToVisualize.values;
69 | var hash = this._hash;
70 | var primitives = this._primitives;
71 |
72 | for (var i = 0, len = entities.length; i < len; i++) {
73 | var entity = entities[i];
74 | var customPatternSensorGraphics = entity._customPatternSensor;
75 |
76 | var position;
77 | var orientation;
78 | var directions;
79 | var data = hash[entity.id];
80 | var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(customPatternSensorGraphics._show, time, true);
81 |
82 | if (show) {
83 | position = Property.getValueOrUndefined(entity._position, time, cachedPosition);
84 | orientation = Property.getValueOrUndefined(entity._orientation, time, cachedOrientation);
85 | directions = Property.getValueOrUndefined(customPatternSensorGraphics._directions, time);
86 | show = defined(position) && defined(orientation) && defined(directions);
87 | }
88 |
89 | if (!show) {
90 | // don't bother creating or updating anything else
91 | if (defined(data)) {
92 | data.primitive.show = false;
93 | }
94 | continue;
95 | }
96 |
97 | var primitive = defined(data) ? data.primitive : undefined;
98 | if (!defined(primitive)) {
99 | primitive = new CustomSensorVolume();
100 | primitive.id = entity;
101 | primitives.add(primitive);
102 |
103 | data = {
104 | primitive: primitive,
105 | position: undefined,
106 | orientation: undefined
107 | };
108 | hash[entity.id] = data;
109 | }
110 |
111 | if (!Cartesian3.equals(position, data.position) || !Quaternion.equals(orientation, data.orientation)) {
112 | Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, matrix3Scratch), position, primitive.modelMatrix);
113 | data.position = Cartesian3.clone(position, data.position);
114 | data.orientation = Quaternion.clone(orientation, data.orientation);
115 | }
116 |
117 | primitive.show = true;
118 | primitive.directions = directions;
119 | primitive.radius = Property.getValueOrDefault(customPatternSensorGraphics._radius, time, defaultRadius);
120 | primitive.lateralSurfaceMaterial = MaterialProperty.getValue(time, customPatternSensorGraphics._lateralSurfaceMaterial, primitive.lateralSurfaceMaterial);
121 | primitive.intersectionColor = Property.getValueOrClonedDefault(customPatternSensorGraphics._intersectionColor, time, defaultIntersectionColor, primitive.intersectionColor);
122 | primitive.intersectionWidth = Property.getValueOrDefault(customPatternSensorGraphics._intersectionWidth, time, defaultIntersectionWidth);
123 | }
124 | return true;
125 | };
126 |
127 | /**
128 | * Returns true if this object was destroyed; otherwise, false.
129 | *
130 | * @returns {Boolean} True if this object was destroyed; otherwise, false.
131 | */
132 | CustomPatternSensorVisualizer.prototype.isDestroyed = function() {
133 | return false;
134 | };
135 |
136 | /**
137 | * Removes and destroys all primitives created by this instance.
138 | */
139 | CustomPatternSensorVisualizer.prototype.destroy = function() {
140 | var entities = this._entitiesToVisualize.values;
141 | var hash = this._hash;
142 | var primitives = this._primitives;
143 | for (var i = entities.length - 1; i > -1; i--) {
144 | removePrimitive(entities[i], hash, primitives);
145 | }
146 | return destroyObject(this);
147 | };
148 |
149 | /**
150 | * @private
151 | */
152 | CustomPatternSensorVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
153 | var i;
154 | var entity;
155 | var entities = this._entitiesToVisualize;
156 | var hash = this._hash;
157 | var primitives = this._primitives;
158 |
159 | for (i = added.length - 1; i > -1; i--) {
160 | entity = added[i];
161 | if (defined(entity._customPatternSensor) && defined(entity._position) && defined(entity._orientation)) {
162 | entities.set(entity.id, entity);
163 | }
164 | }
165 |
166 | for (i = changed.length - 1; i > -1; i--) {
167 | entity = changed[i];
168 | if (defined(entity._customPatternSensor) && defined(entity._position) && defined(entity._orientation)) {
169 | entities.set(entity.id, entity);
170 | } else {
171 | removePrimitive(entity, hash, primitives);
172 | entities.remove(entity.id);
173 | }
174 | }
175 |
176 | for (i = removed.length - 1; i > -1; i--) {
177 | entity = removed[i];
178 | removePrimitive(entity, hash, primitives);
179 | entities.remove(entity.id);
180 | }
181 | };
182 |
183 | export default CustomPatternSensorVisualizer;
184 |
--------------------------------------------------------------------------------
/lib/rectangular/rectangular-sensor-visualizer.js:
--------------------------------------------------------------------------------
1 | import {
2 | AssociativeArray,
3 | Cartesian3,
4 | Color,
5 | defined,
6 | destroyObject,
7 | DeveloperError,
8 | Math as CesiumMath,
9 | Matrix3,
10 | Matrix4,
11 | Quaternion,
12 | MaterialProperty,
13 | Property
14 | } from 'cesium';
15 | import removePrimitive from '../util/remove-primitive';
16 | import RectangularPyramidSensorVolume from './rectangular-pyramid-sensor-volume';
17 |
18 | const defaultIntersectionColor = Color.WHITE;
19 | const defaultIntersectionWidth = 1.0;
20 | const defaultRadius = Number.POSITIVE_INFINITY;
21 |
22 | const matrix3Scratch = new Matrix3();
23 | const cachedPosition = new Cartesian3();
24 | const cachedOrientation = new Quaternion();
25 |
26 | /**
27 | * A {@link Visualizer} which maps {@link Entity#rectangularSensor} to a {@link RectangularSensor}.
28 | * @alias RectangularSensorVisualizer
29 | * @constructor
30 | *
31 | * @param {Scene} scene The scene the primitives will be rendered in.
32 | * @param {EntityCollection} entityCollection The entityCollection to visualize.
33 | */
34 | const RectangularSensorVisualizer = function(scene, entityCollection) {
35 | // >>includeStart('debug', pragmas.debug);
36 | if (!defined(scene)) {
37 | throw new DeveloperError('scene is required.');
38 | }
39 | if (!defined(entityCollection)) {
40 | throw new DeveloperError('entityCollection is required.');
41 | }
42 | // >>includeEnd('debug');
43 |
44 | entityCollection.collectionChanged.addEventListener(RectangularSensorVisualizer.prototype._onCollectionChanged, this);
45 |
46 | this._scene = scene;
47 | this._primitives = scene.primitives;
48 | this._entityCollection = entityCollection;
49 | this._hash = {};
50 | this._entitiesToVisualize = new AssociativeArray();
51 |
52 | this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
53 | };
54 |
55 | /**
56 | * Updates the primitives created by this visualizer to match their
57 | * Entity counterpart at the given time.
58 | *
59 | * @param {JulianDate} time The time to update to.
60 | * @returns {Boolean} This function always returns true.
61 | */
62 | RectangularSensorVisualizer.prototype.update = function(time) {
63 | // >>includeStart('debug', pragmas.debug);
64 | if (!defined(time)) {
65 | throw new DeveloperError('time is required.');
66 | }
67 | // >>includeEnd('debug');
68 |
69 | var entities = this._entitiesToVisualize.values;
70 | var hash = this._hash;
71 | var primitives = this._primitives;
72 |
73 | for (var i = 0, len = entities.length; i < len; i++) {
74 | var entity = entities[i];
75 | var rectangularSensorGraphics = entity._rectangularSensor;
76 |
77 | var position;
78 | var orientation;
79 | var data = hash[entity.id];
80 | var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(rectangularSensorGraphics._show, time, true);
81 |
82 | if (show) {
83 | position = Property.getValueOrUndefined(entity._position, time, cachedPosition);
84 | orientation = Property.getValueOrUndefined(entity._orientation, time, cachedOrientation);
85 | show = defined(position) && defined(orientation);
86 | }
87 |
88 | if (!show) {
89 | // don't bother creating or updating anything else
90 | if (defined(data)) {
91 | data.primitive.show = false;
92 | }
93 | continue;
94 | }
95 |
96 | var primitive = defined(data) ? data.primitive : undefined;
97 | if (!defined(primitive)) {
98 | primitive = new RectangularPyramidSensorVolume();
99 | primitive.id = entity;
100 | primitives.add(primitive);
101 |
102 | data = {
103 | primitive: primitive,
104 | position: undefined,
105 | orientation: undefined
106 | };
107 | hash[entity.id] = data;
108 | }
109 |
110 | if (!Cartesian3.equals(position, data.position) || !Quaternion.equals(orientation, data.orientation)) {
111 | Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, matrix3Scratch), position, primitive.modelMatrix);
112 | data.position = Cartesian3.clone(position, data.position);
113 | data.orientation = Quaternion.clone(orientation, data.orientation);
114 | }
115 |
116 | primitive.show = true;
117 | primitive.xHalfAngle = Property.getValueOrDefault(rectangularSensorGraphics._xHalfAngle, time, CesiumMath.PI_OVER_TWO);
118 | primitive.yHalfAngle = Property.getValueOrDefault(rectangularSensorGraphics._yHalfAngle, time, CesiumMath.PI_OVER_TWO);
119 | primitive.radius = Property.getValueOrDefault(rectangularSensorGraphics._radius, time, defaultRadius);
120 | primitive.lateralSurfaceMaterial = MaterialProperty.getValue(time, rectangularSensorGraphics._lateralSurfaceMaterial, primitive.lateralSurfaceMaterial);
121 | primitive.intersectionColor = Property.getValueOrClonedDefault(rectangularSensorGraphics._intersectionColor, time, defaultIntersectionColor, primitive.intersectionColor);
122 | primitive.intersectionWidth = Property.getValueOrDefault(rectangularSensorGraphics._intersectionWidth, time, defaultIntersectionWidth);
123 | }
124 | return true;
125 | };
126 |
127 | /**
128 | * Returns true if this object was destroyed; otherwise, false.
129 | *
130 | * @returns {Boolean} True if this object was destroyed; otherwise, false.
131 | */
132 | RectangularSensorVisualizer.prototype.isDestroyed = function() {
133 | return false;
134 | };
135 |
136 | /**
137 | * Removes and destroys all primitives created by this instance.
138 | */
139 | RectangularSensorVisualizer.prototype.destroy = function() {
140 | var entities = this._entitiesToVisualize.values;
141 | var hash = this._hash;
142 | var primitives = this._primitives;
143 | for (var i = entities.length - 1; i > -1; i--) {
144 | removePrimitive(entities[i], hash, primitives);
145 | }
146 | return destroyObject(this);
147 | };
148 |
149 | /**
150 | * @private
151 | */
152 | RectangularSensorVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
153 | var i;
154 | var entity;
155 | var entities = this._entitiesToVisualize;
156 | var hash = this._hash;
157 | var primitives = this._primitives;
158 |
159 | for (i = added.length - 1; i > -1; i--) {
160 | entity = added[i];
161 | if (defined(entity._rectangularSensor) && defined(entity._position) && defined(entity._orientation)) {
162 | entities.set(entity.id, entity);
163 | }
164 | }
165 |
166 | for (i = changed.length - 1; i > -1; i--) {
167 | entity = changed[i];
168 | if (defined(entity._rectangularSensor) && defined(entity._position) && defined(entity._orientation)) {
169 | entities.set(entity.id, entity);
170 | } else {
171 | removePrimitive(entity, hash, primitives);
172 | entities.remove(entity.id);
173 | }
174 | }
175 |
176 | for (i = removed.length - 1; i > -1; i--) {
177 | entity = removed[i];
178 | removePrimitive(entity, hash, primitives);
179 | entities.remove(entity.id);
180 | }
181 | };
182 |
183 | export default RectangularSensorVisualizer;
184 |
--------------------------------------------------------------------------------
/lib/initialize.js:
--------------------------------------------------------------------------------
1 | import {
2 | Cartesian3,
3 | Color,
4 | defined,
5 | Spherical,
6 | TimeInterval,
7 | CzmlDataSource,
8 | DataSourceDisplay
9 | } from 'cesium';
10 | import ConicSensorGraphics from './conic/conic-sensor-graphics';
11 | import ConicSensorVisualizer from './conic/conic-sensor-visualizer';
12 | import CustomPatternSensorGraphics from './custom/custom-pattern-sensor-graphics';
13 | import CustomPatternSensorVisualizer from './custom/custom-pattern-sensor-visualizer';
14 | import RectangularSensorGraphics from './rectangular/rectangular-sensor-graphics';
15 | import RectangularSensorVisualizer from './rectangular/rectangular-sensor-visualizer';
16 |
17 | var processPacketData = CzmlDataSource.processPacketData;
18 | var processMaterialPacketData = CzmlDataSource.processMaterialPacketData;
19 |
20 | // eslint-disable-next-line max-params
21 | function processDirectionData(customPatternSensor, directions, interval, sourceUri, entityCollection) {
22 | var i;
23 | var len;
24 | var values = [];
25 | var unitSphericals = directions.unitSpherical;
26 | var sphericals = directions.spherical;
27 | var unitCartesians = directions.unitCartesian;
28 | var cartesians = directions.cartesian;
29 |
30 | if (defined(unitSphericals)) {
31 | for (i = 0, len = unitSphericals.length; i < len; i += 2) {
32 | values.push(new Spherical(unitSphericals[i], unitSphericals[i + 1]));
33 | }
34 | directions.array = values;
35 | } else if (defined(sphericals)) {
36 | for (i = 0, len = sphericals.length; i < len; i += 3) {
37 | values.push(new Spherical(sphericals[i], sphericals[i + 1], sphericals[i + 2]));
38 | }
39 | directions.array = values;
40 | } else if (defined(unitCartesians)) {
41 | for (i = 0, len = unitCartesians.length; i < len; i += 3) {
42 | var tmp = Spherical.fromCartesian3(new Cartesian3(unitCartesians[i], unitCartesians[i + 1], unitCartesians[i + 2]));
43 | Spherical.normalize(tmp, tmp);
44 | values.push(tmp);
45 | }
46 | directions.array = values;
47 | } else if (defined(cartesians)) {
48 | for (i = 0, len = cartesians.length; i < len; i += 3) {
49 | values.push(Spherical.fromCartesian3(new Cartesian3(cartesians[i], cartesians[i + 1], cartesians[i + 2])));
50 | }
51 | directions.array = values;
52 | }
53 | processPacketData(Array, customPatternSensor, 'directions', directions, interval, sourceUri, entityCollection);
54 | }
55 |
56 | // eslint-disable-next-line max-params
57 | function processCommonSensorProperties(sensor, sensorData, interval, sourceUri, entityCollection) {
58 | processPacketData(Boolean, sensor, 'show', sensorData.show, interval, sourceUri, entityCollection);
59 | processPacketData(Number, sensor, 'radius', sensorData.radius, interval, sourceUri, entityCollection);
60 | processPacketData(Boolean, sensor, 'showIntersection', sensorData.showIntersection, interval, sourceUri, entityCollection);
61 | processPacketData(Color, sensor, 'intersectionColor', sensorData.intersectionColor, interval, sourceUri, entityCollection);
62 | processPacketData(Number, sensor, 'intersectionWidth', sensorData.intersectionWidth, interval, sourceUri, entityCollection);
63 | processMaterialPacketData(sensor, 'lateralSurfaceMaterial', sensorData.lateralSurfaceMaterial, interval, sourceUri, entityCollection);
64 | }
65 |
66 | var iso8601Scratch = {
67 | iso8601: undefined
68 | };
69 |
70 | function processConicSensor(entity, packet, entityCollection, sourceUri) {
71 | var conicSensorData = packet.agi_conicSensor;
72 | if (!defined(conicSensorData)) {
73 | return;
74 | }
75 |
76 | var interval;
77 | var intervalString = conicSensorData.interval;
78 | if (defined(intervalString)) {
79 | iso8601Scratch.iso8601 = intervalString;
80 | interval = TimeInterval.fromIso8601(iso8601Scratch);
81 | }
82 |
83 | var conicSensor = entity.conicSensor;
84 | if (!defined(conicSensor)) {
85 | entity.addProperty('conicSensor');
86 | conicSensor = new ConicSensorGraphics();
87 | entity.conicSensor = conicSensor;
88 | }
89 |
90 | processCommonSensorProperties(conicSensor, conicSensorData, interval, sourceUri, entityCollection);
91 | processPacketData(Number, conicSensor, 'innerHalfAngle', conicSensorData.innerHalfAngle, interval, sourceUri, entityCollection);
92 | processPacketData(Number, conicSensor, 'outerHalfAngle', conicSensorData.outerHalfAngle, interval, sourceUri, entityCollection);
93 | processPacketData(Number, conicSensor, 'minimumClockAngle', conicSensorData.minimumClockAngle, interval, sourceUri, entityCollection);
94 | processPacketData(Number, conicSensor, 'maximumClockAngle', conicSensorData.maximumClockAngle, interval, sourceUri, entityCollection);
95 | }
96 |
97 | function processCustomPatternSensor(entity, packet, entityCollection, sourceUri) {
98 | var customPatternSensorData = packet.agi_customPatternSensor;
99 | if (!defined(customPatternSensorData)) {
100 | return;
101 | }
102 |
103 | var interval;
104 | var intervalString = customPatternSensorData.interval;
105 | if (defined(intervalString)) {
106 | iso8601Scratch.iso8601 = intervalString;
107 | interval = TimeInterval.fromIso8601(iso8601Scratch);
108 | }
109 |
110 | var customPatternSensor = entity.customPatternSensor;
111 | if (!defined(customPatternSensor)) {
112 | entity.addProperty('customPatternSensor');
113 | customPatternSensor = new CustomPatternSensorGraphics();
114 | entity.customPatternSensor = customPatternSensor;
115 | }
116 |
117 | processCommonSensorProperties(customPatternSensor, customPatternSensorData, interval, sourceUri, entityCollection);
118 |
119 | // The directions property is a special case value that can be an array of unitSpherical or unit Cartesians.
120 | // We pre-process this into Spherical instances and then process it like any other array.
121 | var directions = customPatternSensorData.directions;
122 | if (defined(directions)) {
123 | if (Array.isArray(directions)) {
124 | var length = directions.length;
125 | for (var i = 0; i < length; i++) {
126 | processDirectionData(customPatternSensor, directions[i], interval, sourceUri, entityCollection);
127 | }
128 | } else {
129 | processDirectionData(customPatternSensor, directions, interval, sourceUri, entityCollection);
130 | }
131 | }
132 | }
133 |
134 | function processRectangularSensor(entity, packet, entityCollection, sourceUri) {
135 | var rectangularSensorData = packet.agi_rectangularSensor;
136 | if (!defined(rectangularSensorData)) {
137 | return;
138 | }
139 |
140 | var interval;
141 | var intervalString = rectangularSensorData.interval;
142 | if (defined(intervalString)) {
143 | iso8601Scratch.iso8601 = intervalString;
144 | interval = TimeInterval.fromIso8601(iso8601Scratch);
145 | }
146 |
147 | var rectangularSensor = entity.rectangularSensor;
148 | if (!defined(rectangularSensor)) {
149 | entity.addProperty('rectangularSensor');
150 | rectangularSensor = new RectangularSensorGraphics();
151 | entity.rectangularSensor = rectangularSensor;
152 | }
153 |
154 | processCommonSensorProperties(rectangularSensor, rectangularSensorData, interval, sourceUri, entityCollection);
155 | processPacketData(Number, rectangularSensor, 'xHalfAngle', rectangularSensorData.xHalfAngle, interval, sourceUri, entityCollection);
156 | processPacketData(Number, rectangularSensor, 'yHalfAngle', rectangularSensorData.yHalfAngle, interval, sourceUri, entityCollection);
157 | }
158 |
159 | var initialized = false;
160 |
161 | export default 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 |
--------------------------------------------------------------------------------
/lib/conic/conic-sensor-visualizer.js:
--------------------------------------------------------------------------------
1 | import {
2 | AssociativeArray,
3 | Cartesian3,
4 | Color,
5 | defined,
6 | destroyObject,
7 | DeveloperError,
8 | Math as CesiumMath,
9 | Matrix3,
10 | Matrix4,
11 | Quaternion,
12 | Spherical,
13 | MaterialProperty,
14 | Property
15 | } from 'cesium';
16 | import CustomSensorVolume from '../custom/custom-sensor-volume';
17 | import removePrimitive from '../util/remove-primitive';
18 |
19 | const defaultIntersectionColor = Color.WHITE;
20 | const defaultIntersectionWidth = 1.0;
21 | const defaultRadius = Number.POSITIVE_INFINITY;
22 |
23 | const matrix3Scratch = new Matrix3();
24 | const cachedPosition = new Cartesian3();
25 | const cachedOrientation = new Quaternion();
26 |
27 | function assignSpherical(index, array, clock, cone) {
28 | var spherical = array[index];
29 | if (!defined(spherical)) {
30 | spherical = new Spherical();
31 | array[index] = spherical;
32 | }
33 | spherical.clock = clock;
34 | spherical.cone = cone;
35 | spherical.magnitude = 1.0;
36 | }
37 |
38 | // eslint-disable-next-line max-params
39 | function computeDirections(primitive, minimumClockAngle, maximumClockAngle, innerHalfAngle, outerHalfAngle) {
40 | var directions = primitive.directions;
41 | var angle;
42 | var i = 0;
43 | var angleStep = CesiumMath.toRadians(2.0);
44 | if (minimumClockAngle === 0.0 && maximumClockAngle === CesiumMath.TWO_PI) {
45 | // No clock angle limits, so this is just a circle.
46 | // There might be a hole but we're ignoring it for now.
47 | for (angle = 0.0; angle < CesiumMath.TWO_PI; angle += angleStep) {
48 | assignSpherical(i++, directions, angle, outerHalfAngle);
49 | }
50 | } else {
51 | // There are clock angle limits.
52 | for (angle = minimumClockAngle; angle < maximumClockAngle; angle += angleStep) {
53 | assignSpherical(i++, directions, angle, outerHalfAngle);
54 | }
55 | assignSpherical(i++, directions, maximumClockAngle, outerHalfAngle);
56 | if (innerHalfAngle) {
57 | for (angle = maximumClockAngle; angle > minimumClockAngle; angle -= angleStep) {
58 | assignSpherical(i++, directions, angle, innerHalfAngle);
59 | }
60 | assignSpherical(i++, directions, minimumClockAngle, innerHalfAngle);
61 | } else {
62 | assignSpherical(i++, directions, maximumClockAngle, 0.0);
63 | }
64 | }
65 | directions.length = i;
66 | primitive.directions = directions;
67 | }
68 |
69 | /**
70 | * A {@link Visualizer} which maps {@link Entity#conicSensor} to a {@link ConicSensor}.
71 | * @alias ConicSensorVisualizer
72 | * @constructor
73 | *
74 | * @param {Scene} scene The scene the primitives will be rendered in.
75 | * @param {EntityCollection} entityCollection The entityCollection to visualize.
76 | */
77 | const ConicSensorVisualizer = function(scene, entityCollection) {
78 | // >>includeStart('debug', pragmas.debug);
79 | if (!defined(scene)) {
80 | throw new DeveloperError('scene is required.');
81 | }
82 | if (!defined(entityCollection)) {
83 | throw new DeveloperError('entityCollection is required.');
84 | }
85 | // >>includeEnd('debug');
86 |
87 | entityCollection.collectionChanged.addEventListener(ConicSensorVisualizer.prototype._onCollectionChanged, this);
88 |
89 | this._scene = scene;
90 | this._primitives = scene.primitives;
91 | this._entityCollection = entityCollection;
92 | this._hash = {};
93 | this._entitiesToVisualize = new AssociativeArray();
94 |
95 | this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
96 | };
97 |
98 | /**
99 | * Updates the primitives created by this visualizer to match their
100 | * Entity counterpart at the given time.
101 | *
102 | * @param {JulianDate} time The time to update to.
103 | * @returns {Boolean} This function always returns true.
104 | */
105 | ConicSensorVisualizer.prototype.update = function(time) {
106 | // >>includeStart('debug', pragmas.debug);
107 | if (!defined(time)) {
108 | throw new DeveloperError('time is required.');
109 | }
110 | // >>includeEnd('debug');
111 |
112 | var entities = this._entitiesToVisualize.values;
113 | var hash = this._hash;
114 | var primitives = this._primitives;
115 |
116 | for (var i = 0, len = entities.length; i < len; i++) {
117 | var entity = entities[i];
118 | var conicSensorGraphics = entity._conicSensor;
119 |
120 | var position;
121 | var orientation;
122 | var data = hash[entity.id];
123 | var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(conicSensorGraphics._show, time, true);
124 |
125 | if (show) {
126 | position = Property.getValueOrUndefined(entity._position, time, cachedPosition);
127 | orientation = Property.getValueOrUndefined(entity._orientation, time, cachedOrientation);
128 | show = defined(position) && defined(orientation);
129 | }
130 |
131 | if (!show) {
132 | // don't bother creating or updating anything else
133 | if (defined(data)) {
134 | data.primitive.show = false;
135 | }
136 | continue;
137 | }
138 |
139 | var primitive = defined(data) ? data.primitive : undefined;
140 | if (!defined(primitive)) {
141 | primitive = new CustomSensorVolume();
142 | primitive.id = entity;
143 | primitives.add(primitive);
144 |
145 | data = {
146 | primitive: primitive,
147 | position: undefined,
148 | orientation: undefined,
149 | minimumClockAngle: undefined,
150 | maximumClockAngle: undefined,
151 | innerHalfAngle: undefined,
152 | outerHalfAngle: undefined
153 | };
154 | hash[entity.id] = data;
155 | }
156 |
157 | if (!Cartesian3.equals(position, data.position) || !Quaternion.equals(orientation, data.orientation)) {
158 | Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, matrix3Scratch), position, primitive.modelMatrix);
159 | data.position = Cartesian3.clone(position, data.position);
160 | data.orientation = Quaternion.clone(orientation, data.orientation);
161 | }
162 |
163 | primitive.show = true;
164 | var minimumClockAngle = Property.getValueOrDefault(conicSensorGraphics._minimumClockAngle, time, 0);
165 | var maximumClockAngle = Property.getValueOrDefault(conicSensorGraphics._maximumClockAngle, time, CesiumMath.TWO_PI);
166 | var innerHalfAngle = Property.getValueOrDefault(conicSensorGraphics._innerHalfAngle, time, 0);
167 | var outerHalfAngle = Property.getValueOrDefault(conicSensorGraphics._outerHalfAngle, time, Math.PI);
168 |
169 | if (minimumClockAngle !== data.minimumClockAngle ||
170 | maximumClockAngle !== data.maximumClockAngle ||
171 | innerHalfAngle !== data.innerHalfAngle ||
172 | outerHalfAngle !== data.outerHalfAngle
173 | ) {
174 | computeDirections(primitive, minimumClockAngle, maximumClockAngle, innerHalfAngle, outerHalfAngle);
175 | data.innerHalfAngle = innerHalfAngle;
176 | data.maximumClockAngle = maximumClockAngle;
177 | data.outerHalfAngle = outerHalfAngle;
178 | data.minimumClockAngle = minimumClockAngle;
179 | }
180 |
181 | primitive.radius = Property.getValueOrDefault(conicSensorGraphics._radius, time, defaultRadius);
182 | primitive.lateralSurfaceMaterial = MaterialProperty.getValue(time, conicSensorGraphics._lateralSurfaceMaterial, primitive.lateralSurfaceMaterial);
183 | primitive.intersectionColor = Property.getValueOrClonedDefault(conicSensorGraphics._intersectionColor, time, defaultIntersectionColor, primitive.intersectionColor);
184 | primitive.intersectionWidth = Property.getValueOrDefault(conicSensorGraphics._intersectionWidth, time, defaultIntersectionWidth);
185 | }
186 | return true;
187 | };
188 |
189 | /**
190 | * Returns true if this object was destroyed; otherwise, false.
191 | *
192 | * @returns {Boolean} True if this object was destroyed; otherwise, false.
193 | */
194 | ConicSensorVisualizer.prototype.isDestroyed = function() {
195 | return false;
196 | };
197 |
198 | /**
199 | * Removes and destroys all primitives created by this instance.
200 | */
201 | ConicSensorVisualizer.prototype.destroy = function() {
202 | var entities = this._entitiesToVisualize.values;
203 | var hash = this._hash;
204 | var primitives = this._primitives;
205 | for (var i = entities.length - 1; i > -1; i--) {
206 | removePrimitive(entities[i], hash, primitives);
207 | }
208 | return destroyObject(this);
209 | };
210 |
211 | /**
212 | * @private
213 | */
214 | ConicSensorVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
215 | var i;
216 | var entity;
217 | var entities = this._entitiesToVisualize;
218 | var hash = this._hash;
219 | var primitives = this._primitives;
220 |
221 | for (i = added.length - 1; i > -1; i--) {
222 | entity = added[i];
223 | if (defined(entity._conicSensor) && defined(entity._position) && defined(entity._orientation)) {
224 | entities.set(entity.id, entity);
225 | }
226 | }
227 |
228 | for (i = changed.length - 1; i > -1; i--) {
229 | entity = changed[i];
230 | if (defined(entity._conicSensor) && defined(entity._position) && defined(entity._orientation)) {
231 | entities.set(entity.id, entity);
232 | } else {
233 | removePrimitive(entity, hash, primitives);
234 | entities.remove(entity.id);
235 | }
236 | }
237 |
238 | for (i = removed.length - 1; i > -1; i--) {
239 | entity = removed[i];
240 | removePrimitive(entity, hash, primitives);
241 | entities.remove(entity.id);
242 | }
243 | };
244 |
245 | export default ConicSensorVisualizer;
246 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | import {
2 | BoundingSphere,
3 | Cartesian3,
4 | Color,
5 | combine,
6 | ComponentDatatype,
7 | defined,
8 | destroyObject,
9 | DeveloperError,
10 | Frozen,
11 | Matrix4,
12 | PrimitiveType,
13 | Buffer,
14 | BufferUsage,
15 | DrawCommand,
16 | Pass,
17 | RenderState,
18 | ShaderProgram,
19 | ShaderSource,
20 | VertexArray,
21 | BlendingState,
22 | CullFace,
23 | Material,
24 | SceneMode
25 | } from 'cesium';
26 |
27 | // eslint-disable-next-line import/extensions
28 | import SensorVolume from '../sensor-volume.glsl';
29 | // eslint-disable-next-line import/extensions
30 | import CustomSensorVolumeFS from './custom-sensor-volume-fs.glsl';
31 | // eslint-disable-next-line import/extensions
32 | import CustomSensorVolumeVS from './custom-sensor-volume-vs.glsl';
33 |
34 | const attributeLocations = {
35 | position: 0,
36 | normal: 1
37 | };
38 |
39 | const FAR = 5906376272000.0; // distance from the Sun to Pluto in meters.
40 |
41 | /**
42 | * DOC_TBA
43 | *
44 | * @alias CustomSensorVolume
45 | * @constructor
46 | */
47 | const CustomSensorVolume = function(options) {
48 | options = options ?? Frozen.EMPTY_OBJECT;
49 |
50 | this._pickId = undefined;
51 | this._pickPrimitive = options._pickPrimitive ?? this;
52 |
53 | this._frontFaceColorCommand = new DrawCommand();
54 | this._backFaceColorCommand = new DrawCommand();
55 | this._pickCommand = new DrawCommand();
56 |
57 | this._boundingSphere = new BoundingSphere();
58 | this._boundingSphereWC = new BoundingSphere();
59 |
60 | this._frontFaceColorCommand.primitiveType = PrimitiveType.TRIANGLES;
61 | this._frontFaceColorCommand.boundingVolume = this._boundingSphereWC;
62 | this._frontFaceColorCommand.owner = this;
63 |
64 | this._backFaceColorCommand.primitiveType = this._frontFaceColorCommand.primitiveType;
65 | this._backFaceColorCommand.boundingVolume = this._frontFaceColorCommand.boundingVolume;
66 | this._backFaceColorCommand.owner = this;
67 |
68 | this._pickCommand.primitiveType = this._frontFaceColorCommand.primitiveType;
69 | this._pickCommand.boundingVolume = this._frontFaceColorCommand.boundingVolume;
70 | this._pickCommand.owner = this;
71 |
72 | /**
73 | * true if this sensor will be shown; otherwise, false
74 | *
75 | * @type {Boolean}
76 | * @default true
77 | */
78 | this.show = options.show ?? true;
79 |
80 | /**
81 | * When true, a polyline is shown where the sensor outline intersections the globe.
82 | *
83 | * @type {Boolean}
84 | *
85 | * @default true
86 | *
87 | * @see CustomSensorVolume#intersectionColor
88 | */
89 | this.showIntersection = options.showIntersection ?? true;
90 |
91 | /**
92 | *
93 | * Determines if a sensor intersecting the ellipsoid is drawn through the ellipsoid and potentially out
94 | * to the other side, or if the part of the sensor intersecting the ellipsoid stops at the ellipsoid.
95 | *
96 | *
97 | * @type {Boolean}
98 | * @default false
99 | */
100 | this.showThroughEllipsoid = options.showThroughEllipsoid ?? false;
101 | this._showThroughEllipsoid = this.showThroughEllipsoid;
102 |
103 | /**
104 | * The 4x4 transformation matrix that transforms this sensor from model to world coordinates. In it's model
105 | * coordinates, the sensor's principal direction is along the positive z-axis. The clock angle, sometimes
106 | * called azimuth, is the angle in the sensor's X-Y plane measured from the positive X-axis toward the positive
107 | * Y-axis. The cone angle, sometimes called elevation, is the angle out of the X-Y plane along the positive Z-axis.
108 | *
109 | *
110 | *
111 | * Model coordinate system for a custom sensor
112 | *
113 | *
114 | * @type {Matrix4}
115 | * @default {@link Matrix4.IDENTITY}
116 | *
117 | * @example
118 | * // The sensor's vertex is located on the surface at -75.59777 degrees longitude and 40.03883 degrees latitude.
119 | * // The sensor's opens upward, along the surface normal.
120 | * var center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
121 | * sensor.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
122 | */
123 | this.modelMatrix = Matrix4.clone(options.modelMatrix ?? Matrix4.IDENTITY);
124 | this._modelMatrix = new Matrix4();
125 |
126 | /**
127 | * DOC_TBA
128 | *
129 | * @type {Number}
130 | * @default {@link Number.POSITIVE_INFINITY}
131 | */
132 | this.radius = options.radius ?? Number.POSITIVE_INFINITY;
133 |
134 | this._directions = undefined;
135 | this._directionsDirty = false;
136 | this.directions = defined(options.directions) ? options.directions : [];
137 |
138 | /**
139 | * The surface appearance of the sensor. This can be one of several built-in {@link Material} objects or a custom material, scripted with
140 | * {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}.
141 | *
142 | * The default material is Material.ColorType.
143 | *
336 | * Do not call this function directly. This is documented just to
337 | * list the exceptions that may be propagated when the scene is rendered:
338 | *
339 | *
340 | * @exception {DeveloperError} this.radius must be greater than or equal to zero.
341 | * @exception {DeveloperError} this.lateralSurfaceMaterial must be defined.
342 | */
343 | // eslint-disable-next-line complexity
344 | CustomSensorVolume.prototype.update = function(frameState) {
345 | this._mode = frameState.mode;
346 | if (!this.show || this._mode !== SceneMode.SCENE3D) {
347 | return;
348 | }
349 |
350 | var context = frameState.context;
351 | var commandList = frameState.commandList;
352 |
353 | // >>includeStart('debug', pragmas.debug);
354 | if (this.radius < 0.0) {
355 | throw new DeveloperError('this.radius must be greater than or equal to zero.');
356 | }
357 | if (!defined(this.lateralSurfaceMaterial)) {
358 | throw new DeveloperError('this.lateralSurfaceMaterial must be defined.');
359 | }
360 | // >>includeEnd('debug');
361 |
362 | var translucent = this.lateralSurfaceMaterial.isTranslucent();
363 |
364 | // Initial render state creation
365 | if ((this._showThroughEllipsoid !== this.showThroughEllipsoid) ||
366 | (!defined(this._frontFaceColorCommand.renderState)) ||
367 | (this._translucent !== translucent)
368 | ) {
369 | this._showThroughEllipsoid = this.showThroughEllipsoid;
370 | this._translucent = translucent;
371 |
372 | var rs;
373 |
374 | if (translucent) {
375 | rs = RenderState.fromCache({
376 | depthTest: {
377 | // This would be better served by depth testing with a depth buffer that does not
378 | // include the ellipsoid depth - or a g-buffer containing an ellipsoid mask
379 | // so we can selectively depth test.
380 | enabled: !this.showThroughEllipsoid
381 | },
382 | depthMask: false,
383 | blending: BlendingState.ALPHA_BLEND,
384 | cull: {
385 | enabled: true,
386 | face: CullFace.BACK
387 | }
388 | });
389 |
390 | this._frontFaceColorCommand.renderState = rs;
391 | this._frontFaceColorCommand.pass = Pass.TRANSLUCENT;
392 |
393 | rs = RenderState.fromCache({
394 | depthTest: {
395 | enabled: !this.showThroughEllipsoid
396 | },
397 | depthMask: false,
398 | blending: BlendingState.ALPHA_BLEND,
399 | cull: {
400 | enabled: true,
401 | face: CullFace.FRONT
402 | }
403 | });
404 |
405 | this._backFaceColorCommand.renderState = rs;
406 | this._backFaceColorCommand.pass = Pass.TRANSLUCENT;
407 |
408 | rs = RenderState.fromCache({
409 | depthTest: {
410 | enabled: !this.showThroughEllipsoid
411 | },
412 | depthMask: false,
413 | blending: BlendingState.ALPHA_BLEND
414 | });
415 | this._pickCommand.renderState = rs;
416 | } else {
417 | rs = RenderState.fromCache({
418 | depthTest: {
419 | enabled: true
420 | },
421 | depthMask: true
422 | });
423 | this._frontFaceColorCommand.renderState = rs;
424 | this._frontFaceColorCommand.pass = Pass.OPAQUE;
425 |
426 | rs = RenderState.fromCache({
427 | depthTest: {
428 | enabled: true
429 | },
430 | depthMask: true
431 | });
432 | this._pickCommand.renderState = rs;
433 | }
434 | }
435 |
436 | // Recreate vertex buffer when directions change
437 | var directionsChanged = this._directionsDirty;
438 | if (directionsChanged) {
439 | this._directionsDirty = false;
440 | this._va = this._va && this._va.destroy();
441 |
442 | var directions = this._directions;
443 | if (directions && (directions.length >= 3)) {
444 | this._frontFaceColorCommand.vertexArray = createVertexArray(this, context);
445 | this._backFaceColorCommand.vertexArray = this._frontFaceColorCommand.vertexArray;
446 | this._pickCommand.vertexArray = this._frontFaceColorCommand.vertexArray;
447 | }
448 | }
449 |
450 | if (!defined(this._frontFaceColorCommand.vertexArray)) {
451 | return;
452 | }
453 |
454 | var pass = frameState.passes;
455 |
456 | var modelMatrixChanged = !Matrix4.equals(this.modelMatrix, this._modelMatrix);
457 | if (modelMatrixChanged) {
458 | Matrix4.clone(this.modelMatrix, this._modelMatrix);
459 | }
460 |
461 | if (directionsChanged || modelMatrixChanged) {
462 | BoundingSphere.transform(this._boundingSphere, this.modelMatrix, this._boundingSphereWC);
463 | }
464 |
465 | this._frontFaceColorCommand.modelMatrix = this.modelMatrix;
466 | this._backFaceColorCommand.modelMatrix = this._frontFaceColorCommand.modelMatrix;
467 | this._pickCommand.modelMatrix = this._frontFaceColorCommand.modelMatrix;
468 |
469 | var materialChanged = this._lateralSurfaceMaterial !== this.lateralSurfaceMaterial;
470 | this._lateralSurfaceMaterial = this.lateralSurfaceMaterial;
471 | this._lateralSurfaceMaterial.update(context);
472 |
473 | if (pass.render) {
474 | var frontFaceColorCommand = this._frontFaceColorCommand;
475 | var backFaceColorCommand = this._backFaceColorCommand;
476 |
477 | // Recompile shader when material changes
478 | if (materialChanged || !defined(frontFaceColorCommand.shaderProgram)) {
479 | var fsSource = new ShaderSource({
480 | sources: [SensorVolume, this._lateralSurfaceMaterial.shaderSource, CustomSensorVolumeFS]
481 | });
482 |
483 | frontFaceColorCommand.shaderProgram = ShaderProgram.replaceCache({
484 | context: context,
485 | shaderProgram: frontFaceColorCommand.shaderProgram,
486 | vertexShaderSource: CustomSensorVolumeVS,
487 | fragmentShaderSource: fsSource,
488 | attributeLocations: attributeLocations
489 | });
490 |
491 | frontFaceColorCommand.uniformMap = combine(this._uniforms, this._lateralSurfaceMaterial._uniforms);
492 |
493 | backFaceColorCommand.shaderProgram = frontFaceColorCommand.shaderProgram;
494 | backFaceColorCommand.uniformMap = combine(this._uniforms, this._lateralSurfaceMaterial._uniforms);
495 | // eslint-disable-next-line camelcase
496 | backFaceColorCommand.uniformMap.u_normalDirection = function() {
497 | return -1.0;
498 | };
499 | }
500 |
501 | if (translucent) {
502 | commandList.push(this._backFaceColorCommand, this._frontFaceColorCommand);
503 | } else {
504 | commandList.push(this._frontFaceColorCommand);
505 | }
506 | }
507 |
508 | if (pass.pick) {
509 | var pickCommand = this._pickCommand;
510 |
511 | if (!defined(this._pickId) || (this._id !== this.id)) {
512 | this._id = this.id;
513 | this._pickId = this._pickId && this._pickId.destroy();
514 | this._pickId = context.createPickId({
515 | primitive: this._pickPrimitive,
516 | id: this.id
517 | });
518 | }
519 |
520 | // Recompile shader when material changes
521 | if (materialChanged || !defined(pickCommand.shaderProgram)) {
522 | var pickFS = new ShaderSource({
523 | sources: [SensorVolume, this._lateralSurfaceMaterial.shaderSource, CustomSensorVolumeFS],
524 | pickColorQualifier: 'uniform'
525 | });
526 |
527 | pickCommand.shaderProgram = ShaderProgram.replaceCache({
528 | context: context,
529 | shaderProgram: pickCommand.shaderProgram,
530 | vertexShaderSource: CustomSensorVolumeVS,
531 | fragmentShaderSource: pickFS,
532 | attributeLocations: attributeLocations
533 | });
534 |
535 | var that = this;
536 | var uniforms = {
537 | // eslint-disable-next-line camelcase
538 | czm_pickColor: function() {
539 | return that._pickId.color;
540 | }
541 | };
542 | pickCommand.uniformMap = combine(combine(this._uniforms, this._lateralSurfaceMaterial._uniforms), uniforms);
543 | }
544 |
545 | pickCommand.pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE;
546 | commandList.push(pickCommand);
547 | }
548 | };
549 |
550 | /**
551 | * DOC_TBA
552 | */
553 | CustomSensorVolume.prototype.isDestroyed = function() {
554 | return false;
555 | };
556 |
557 | /**
558 | * DOC_TBA
559 | */
560 | CustomSensorVolume.prototype.destroy = function() {
561 | this._frontFaceColorCommand.vertexArray = this._frontFaceColorCommand.vertexArray && this._frontFaceColorCommand.vertexArray.destroy();
562 | this._frontFaceColorCommand.shaderProgram = this._frontFaceColorCommand.shaderProgram && this._frontFaceColorCommand.shaderProgram.destroy();
563 | this._pickCommand.shaderProgram = this._pickCommand.shaderProgram && this._pickCommand.shaderProgram.destroy();
564 | this._pickId = this._pickId && this._pickId.destroy();
565 | return destroyObject(this);
566 | };
567 |
568 | export default CustomSensorVolume;
569 |
--------------------------------------------------------------------------------
/dist/cesium-sensor-volumes.es.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Cesium Sensor Volumes - https://github.com/Flowm/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/Flowm/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 | import{createPropertyDescriptor as i,createMaterialPropertyDescriptor as t,defined as e,DeveloperError as n,Event as o,Frozen as r,Cartesian3 as s,SceneMode as a,RenderState as l,BlendingState as h,CullFace as c,Pass as u,Matrix4 as d,BoundingSphere as m,ShaderSource as f,ShaderProgram as _,combine as p,destroyObject as C,DrawCommand as g,PrimitiveType as v,Material as w,Color as S,Buffer as y,BufferUsage as A,ComponentDatatype as M,VertexArray as I,Matrix3 as x,Quaternion as T,AssociativeArray as b,Property as E,Math as k,MaterialProperty as H,Spherical as V,clone as W,CzmlDataSource as P,DataSourceDisplay as O,TimeInterval as F}from"cesium";const z=function(i){this._minimumClockAngle=void 0,this._minimumClockAngleSubscription=void 0,this._maximumClockAngle=void 0,this._maximumClockAngleSubscription=void 0,this._innerHalfAngle=void 0,this._innerHalfAngleSubscription=void 0,this._outerHalfAngle=void 0,this._outerHalfAngleSubscription=void 0,this._lateralSurfaceMaterial=void 0,this._lateralSurfaceMaterialSubscription=void 0,this._intersectionColor=void 0,this._intersectionColorSubscription=void 0,this._intersectionWidth=void 0,this._intersectionWidthSubscription=void 0,this._showIntersection=void 0,this._showIntersectionSubscription=void 0,this._radius=void 0,this._radiusSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._definitionChanged=new o,this.merge(i??r.EMPTY_OBJECT)};Object.defineProperties(z.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},minimumClockAngle:i("minimumClockAngle"),maximumClockAngle:i("maximumClockAngle"),innerHalfAngle:i("innerHalfAngle"),outerHalfAngle:i("outerHalfAngle"),lateralSurfaceMaterial:t("lateralSurfaceMaterial"),intersectionColor:i("intersectionColor"),intersectionWidth:i("intersectionWidth"),showIntersection:i("showIntersection"),radius:i("radius"),show:i("show")}),z.prototype.clone=function(i){return e(i)||(i=new z),i.show=this.show,i.innerHalfAngle=this.innerHalfAngle,i.outerHalfAngle=this.outerHalfAngle,i.minimumClockAngle=this.minimumClockAngle,i.maximumClockAngle=this.maximumClockAngle,i.radius=this.radius,i.showIntersection=this.showIntersection,i.intersectionColor=this.intersectionColor,i.intersectionWidth=this.intersectionWidth,i.lateralSurfaceMaterial=this.lateralSurfaceMaterial,i},z.prototype.merge=function(i){if(!e(i))throw new n("source is required.");this.show=this.show??i.show,this.innerHalfAngle=this.innerHalfAngle??i.innerHalfAngle,this.outerHalfAngle=this.outerHalfAngle??i.outerHalfAngle,this.minimumClockAngle=this.minimumClockAngle??i.minimumClockAngle,this.maximumClockAngle=this.maximumClockAngle??i.maximumClockAngle,this.radius=this.radius??i.radius,this.showIntersection=this.showIntersection??i.showIntersection,this.intersectionColor=this.intersectionColor??i.intersectionColor,this.intersectionWidth=this.intersectionWidth??i.intersectionWidth,this.lateralSurfaceMaterial=this.lateralSurfaceMaterial??i.lateralSurfaceMaterial};var D="#version 300 es\n\nuniform vec4 u_intersectionColor;\nuniform float u_intersectionWidth;\n\nbool inSensorShadow(vec3 coneVertexWC, vec3 pointWC)\n{\n \n vec3 D = czm_ellipsoidInverseRadii;\n\n \n vec3 q = D * coneVertexWC;\n float qMagnitudeSquared = dot(q, q);\n float test = qMagnitudeSquared - 1.0;\n\n \n vec3 temp = D * pointWC - q;\n float d = dot(temp, q);\n\n \n return (d < -test) && (d / length(temp) < -sqrt(test));\n}\n\nvec4 getIntersectionColor()\n{\n return u_intersectionColor;\n}\n\nfloat getIntersectionWidth()\n{\n return u_intersectionWidth;\n}\n\nvec2 sensor2dTextureCoordinates(float sensorRadius, vec3 pointMC)\n{\n \n float t = pointMC.z / sensorRadius;\n float s = 1.0 + (atan(pointMC.y, pointMC.x) / czm_twoPi);\n s = s - floor(s);\n\n return vec2(s, t);\n}\n",R="#version 300 es\n\nuniform bool u_showIntersection;\nuniform bool u_showThroughEllipsoid;\n\nuniform float u_sensorRadius;\nuniform float u_normalDirection;\n\nin vec3 v_positionWC;\nin vec3 v_positionEC;\nin vec3 v_normalEC;\n\nvec4 getColor(float sensorRadius, vec3 pointEC)\n{\n czm_materialInput materialInput;\n\n vec3 pointMC = (czm_inverseModelView * vec4(pointEC, 1.0)).xyz;\n materialInput.st = sensor2dTextureCoordinates(sensorRadius, pointMC);\n materialInput.str = pointMC / sensorRadius;\n\n vec3 positionToEyeEC = -v_positionEC;\n materialInput.positionToEyeEC = positionToEyeEC;\n\n vec3 normalEC = normalize(v_normalEC);\n materialInput.normalEC = u_normalDirection * normalEC;\n\n czm_material material = czm_getMaterial(materialInput);\n return mix(czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC), vec4(material.diffuse, material.alpha), 0.4);\n}\n\nbool isOnBoundary(float value, float epsilon)\n{\n float width = getIntersectionWidth();\n float tolerance = width * epsilon;\n\n float delta = max(abs(dFdx(value)), abs(dFdy(value)));\n float pixels = width * delta;\n float temp = abs(value);\n \n \n \n \n \n \n \n return temp < tolerance && temp < pixels || (delta < 10.0 * tolerance && temp - delta < tolerance && temp < pixels);\n}\n\nvec4 shade(bool isOnBoundary)\n{\n if (u_showIntersection && isOnBoundary)\n {\n return getIntersectionColor();\n }\n return getColor(u_sensorRadius, v_positionEC);\n}\n\nfloat ellipsoidSurfaceFunction(vec3 point)\n{\n vec3 scaled = czm_ellipsoidInverseRadii * point;\n return dot(scaled, scaled) - 1.0;\n}\n\nvoid main()\n{\n vec3 sensorVertexWC = czm_model[3].xyz; \n vec3 sensorVertexEC = czm_modelView[3].xyz; \n\n float ellipsoidValue = ellipsoidSurfaceFunction(v_positionWC);\n\n \n if (!u_showThroughEllipsoid)\n {\n \n \n if (ellipsoidValue < 0.0)\n {\n discard;\n }\n\n \n if (inSensorShadow(sensorVertexWC, v_positionWC))\n {\n discard;\n }\n }\n\n \n \n if (distance(v_positionEC, sensorVertexEC) > u_sensorRadius)\n {\n discard;\n }\n\n \n bool isOnEllipsoid = isOnBoundary(ellipsoidValue, czm_epsilon3);\n out_FragColor = shade(isOnEllipsoid);\n}\n",N="#version 300 es\n\nin vec4 position;\nin vec3 normal;\n\nout vec3 v_positionWC;\nout vec3 v_positionEC;\nout vec3 v_normalEC;\n\nvoid main()\n{\n gl_Position = czm_modelViewProjection * position;\n v_positionWC = (czm_model * position).xyz;\n v_positionEC = (czm_modelView * position).xyz;\n v_normalEC = czm_normal * normal;\n}\n";const q={position:0,normal:1},B=5906376272e3,L=function(i){i=i??r.EMPTY_OBJECT,this._pickId=void 0,this._pickPrimitive=i._pickPrimitive??this,this._frontFaceColorCommand=new g,this._backFaceColorCommand=new g,this._pickCommand=new g,this._boundingSphere=new m,this._boundingSphereWC=new m,this._frontFaceColorCommand.primitiveType=v.TRIANGLES,this._frontFaceColorCommand.boundingVolume=this._boundingSphereWC,this._frontFaceColorCommand.owner=this,this._backFaceColorCommand.primitiveType=this._frontFaceColorCommand.primitiveType,this._backFaceColorCommand.boundingVolume=this._frontFaceColorCommand.boundingVolume,this._backFaceColorCommand.owner=this,this._pickCommand.primitiveType=this._frontFaceColorCommand.primitiveType,this._pickCommand.boundingVolume=this._frontFaceColorCommand.boundingVolume,this._pickCommand.owner=this,this.show=i.show??!0,this.showIntersection=i.showIntersection??!0,this.showThroughEllipsoid=i.showThroughEllipsoid??!1,this._showThroughEllipsoid=this.showThroughEllipsoid,this.modelMatrix=d.clone(i.modelMatrix??d.IDENTITY),this._modelMatrix=new d,this.radius=i.radius??Number.POSITIVE_INFINITY,this._directions=void 0,this._directionsDirty=!1,this.directions=e(i.directions)?i.directions:[],this.lateralSurfaceMaterial=e(i.lateralSurfaceMaterial)?i.lateralSurfaceMaterial:w.fromType(w.ColorType),this._lateralSurfaceMaterial=void 0,this._translucent=void 0,this.intersectionColor=S.clone(i.intersectionColor??S.WHITE),this.intersectionWidth=i.intersectionWidth??5,this.id=i.id,this._id=void 0;var t=this;this._uniforms={u_showThroughEllipsoid:function(){return t.showThroughEllipsoid},u_showIntersection:function(){return t.showIntersection},u_sensorRadius:function(){return isFinite(t.radius)?t.radius:B},u_intersectionColor:function(){return t.intersectionColor},u_intersectionWidth:function(){return t.intersectionWidth},u_normalDirection:function(){return 1}},this._mode=a.SCENE3D};Object.defineProperties(L.prototype,{directions:{get:function(){return this._directions},set:function(i){this._directions=i,this._directionsDirty=!0}}});const U=new s,Y=new s,j=new s;const Q=new s;function G(i,t){for(var e=function(i){for(var t=i._directions,e=t.length,n=new Float32Array(3*e),o=isFinite(i.radius)?i.radius:B,r=[s.ZERO],a=e-2,l=e-1,h=0;h=3&&(this._frontFaceColorCommand.vertexArray=G(this,t),this._backFaceColorCommand.vertexArray=this._frontFaceColorCommand.vertexArray,this._pickCommand.vertexArray=this._frontFaceColorCommand.vertexArray)}if(e(this._frontFaceColorCommand.vertexArray)){var v=i.passes,w=!d.equals(this.modelMatrix,this._modelMatrix);w&&d.clone(this.modelMatrix,this._modelMatrix),(C||w)&&m.transform(this._boundingSphere,this.modelMatrix,this._boundingSphereWC),this._frontFaceColorCommand.modelMatrix=this.modelMatrix,this._backFaceColorCommand.modelMatrix=this._frontFaceColorCommand.modelMatrix,this._pickCommand.modelMatrix=this._frontFaceColorCommand.modelMatrix;var S=this._lateralSurfaceMaterial!==this.lateralSurfaceMaterial;if(this._lateralSurfaceMaterial=this.lateralSurfaceMaterial,this._lateralSurfaceMaterial.update(t),v.render){var y=this._frontFaceColorCommand,A=this._backFaceColorCommand;if(S||!e(y.shaderProgram)){var M=new f({sources:[D,this._lateralSurfaceMaterial.shaderSource,R]});y.shaderProgram=_.replaceCache({context:t,shaderProgram:y.shaderProgram,vertexShaderSource:N,fragmentShaderSource:M,attributeLocations:q}),y.uniformMap=p(this._uniforms,this._lateralSurfaceMaterial._uniforms),A.shaderProgram=y.shaderProgram,A.uniformMap=p(this._uniforms,this._lateralSurfaceMaterial._uniforms),A.uniformMap.u_normalDirection=function(){return-1}}s?o.push(this._backFaceColorCommand,this._frontFaceColorCommand):o.push(this._frontFaceColorCommand)}if(v.pick){var I=this._pickCommand;if(e(this._pickId)&&this._id===this.id||(this._id=this.id,this._pickId=this._pickId&&this._pickId.destroy(),this._pickId=t.createPickId({primitive:this._pickPrimitive,id:this.id})),S||!e(I.shaderProgram)){var x=new f({sources:[D,this._lateralSurfaceMaterial.shaderSource,R],pickColorQualifier:"uniform"});I.shaderProgram=_.replaceCache({context:t,shaderProgram:I.shaderProgram,vertexShaderSource:N,fragmentShaderSource:x,attributeLocations:q});var T=this,b={czm_pickColor:function(){return T._pickId.color}};I.uniformMap=p(p(this._uniforms,this._lateralSurfaceMaterial._uniforms),b)}I.pass=s?u.TRANSLUCENT:u.OPAQUE,o.push(I)}}}},L.prototype.isDestroyed=function(){return!1},L.prototype.destroy=function(){return this._frontFaceColorCommand.vertexArray=this._frontFaceColorCommand.vertexArray&&this._frontFaceColorCommand.vertexArray.destroy(),this._frontFaceColorCommand.shaderProgram=this._frontFaceColorCommand.shaderProgram&&this._frontFaceColorCommand.shaderProgram.destroy(),this._pickCommand.shaderProgram=this._pickCommand.shaderProgram&&this._pickCommand.shaderProgram.destroy(),this._pickId=this._pickId&&this._pickId.destroy(),C(this)};const K=S.WHITE,Z=Number.POSITIVE_INFINITY,X=new x,$=new s,ii=new T;function ti(i,t,n,o){var r=t[i];e(r)||(r=new V,t[i]=r),r.clock=n,r.cone=o,r.magnitude=1}function ei(i,t,e,n,o){var r,s=i.directions,a=0,l=k.toRadians(2);if(0===t&&e===k.TWO_PI)for(r=0;rt;r-=l)ti(a++,s,r,n);ti(a++,s,t,n)}else ti(a++,s,e,0)}s.length=a,i.directions=s}const ni=function(i,t){if(!e(i))throw new n("scene is required.");if(!e(t))throw new n("entityCollection is required.");t.collectionChanged.addEventListener(ni.prototype._onCollectionChanged,this),this._scene=i,this._primitives=i.primitives,this._entityCollection=t,this._hash={},this._entitiesToVisualize=new b,this._onCollectionChanged(t,t.values,[],[])};ni.prototype.update=function(i){if(!e(i))throw new n("time is required.");for(var t=this._entitiesToVisualize.values,o=this._hash,r=this._primitives,a=0,l=t.length;a-1;n--)J(i[n],t,e);return C(this)},ni.prototype._onCollectionChanged=function(i,t,n,o){var r,s,a=this._entitiesToVisualize,l=this._hash,h=this._primitives;for(r=t.length-1;r>-1;r--)s=t[r],e(s._conicSensor)&&e(s._position)&&e(s._orientation)&&a.set(s.id,s);for(r=o.length-1;r>-1;r--)s=o[r],e(s._conicSensor)&&e(s._position)&&e(s._orientation)?a.set(s.id,s):(J(s,l,h),a.remove(s.id));for(r=n.length-1;r>-1;r--)J(s=n[r],l,h),a.remove(s.id)};const oi=function(i){this._directions=void 0,this._directionsSubscription=void 0,this._lateralSurfaceMaterial=void 0,this._lateralSurfaceMaterialSubscription=void 0,this._intersectionColor=void 0,this._intersectionColorSubscription=void 0,this._intersectionWidth=void 0,this._intersectionWidthSubscription=void 0,this._showIntersection=void 0,this._showIntersectionSubscription=void 0,this._radius=void 0,this._radiusSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._definitionChanged=new o,this.merge(i??r.EMPTY_OBJECT)};Object.defineProperties(oi.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},directions:i("directions"),lateralSurfaceMaterial:t("lateralSurfaceMaterial"),intersectionColor:i("intersectionColor"),intersectionWidth:i("intersectionWidth"),showIntersection:i("showIntersection"),radius:i("radius"),show:i("show")}),oi.prototype.clone=function(i){return e(i)||(i=new oi),i.directions=this.directions,i.radius=this.radius,i.show=this.show,i.showIntersection=this.showIntersection,i.intersectionColor=this.intersectionColor,i.intersectionWidth=this.intersectionWidth,i.lateralSurfaceMaterial=this.lateralSurfaceMaterial,i},oi.prototype.merge=function(i){if(!e(i))throw new n("source is required.");this.directions=this.directions??i.directions,this.radius=this.radius??i.radius,this.show=this.show??i.show,this.showIntersection=this.showIntersection??i.showIntersection,this.intersectionColor=this.intersectionColor??i.intersectionColor,this.intersectionWidth=this.intersectionWidth??i.intersectionWidth,this.lateralSurfaceMaterial=this.lateralSurfaceMaterial??i.lateralSurfaceMaterial};const ri=S.WHITE,si=Number.POSITIVE_INFINITY,ai=new x,li=new s,hi=new T,ci=function(i,t){if(!e(i))throw new n("scene is required.");if(!e(t))throw new n("entityCollection is required.");t.collectionChanged.addEventListener(ci.prototype._onCollectionChanged,this),this._scene=i,this._primitives=i.primitives,this._entityCollection=t,this._hash={},this._entitiesToVisualize=new b,this._onCollectionChanged(t,t.values,[],[])};ci.prototype.update=function(i){if(!e(i))throw new n("time is required.");for(var t=this._entitiesToVisualize.values,o=this._hash,r=this._primitives,a=0,l=t.length;a-1;n--)J(i[n],t,e);return C(this)},ci.prototype._onCollectionChanged=function(i,t,n,o){var r,s,a=this._entitiesToVisualize,l=this._hash,h=this._primitives;for(r=t.length-1;r>-1;r--)s=t[r],e(s._customPatternSensor)&&e(s._position)&&e(s._orientation)&&a.set(s.id,s);for(r=o.length-1;r>-1;r--)s=o[r],e(s._customPatternSensor)&&e(s._position)&&e(s._orientation)?a.set(s.id,s):(J(s,l,h),a.remove(s.id));for(r=n.length-1;r>-1;r--)J(s=n[r],l,h),a.remove(s.id)};const ui=function(){this._xHalfAngle=void 0,this._xHalfAngleSubscription=void 0,this._yHalfAngle=void 0,this._yHalfAngleSubscription=void 0,this._lateralSurfaceMaterial=void 0,this._lateralSurfaceMaterialSubscription=void 0,this._intersectionColor=void 0,this._intersectionColorSubscription=void 0,this._intersectionWidth=void 0,this._intersectionWidthSubscription=void 0,this._showIntersection=void 0,this._showIntersectionSubscription=void 0,this._radius=void 0,this._radiusSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._definitionChanged=new o};function di(i,t,n,o){var r=t[i];e(r)||(r=new V,t[i]=r),r.clock=n,r.cone=o,r.magnitude=1}function mi(i){var t=i._customSensor.directions,e=Math.tan(Math.min(i._xHalfAngle,k.toRadians(89))),n=Math.tan(Math.min(i._yHalfAngle,k.toRadians(89))),o=Math.atan(e/n),r=Math.atan(Math.sqrt(e*e+n*n));di(0,t,o,r),di(1,t,k.toRadians(180)-o,r),di(2,t,k.toRadians(180)+o,r),di(3,t,-o,r),t.length=4,i._customSensor.directions=t}Object.defineProperties(ui.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},xHalfAngle:i("xHalfAngle"),yHalfAngle:i("yHalfAngle"),lateralSurfaceMaterial:i("lateralSurfaceMaterial"),intersectionColor:i("intersectionColor"),intersectionWidth:i("intersectionWidth"),showIntersection:i("showIntersection"),radius:i("radius"),show:i("show")}),ui.prototype.clone=function(i){return e(i)||(i=new ui),i.xHalfAngle=this.xHalfAngle,i.yHalfAngle=this.yHalfAngle,i.radius=this.radius,i.show=this.show,i.showIntersection=this.showIntersection,i.intersectionColor=this.intersectionColor,i.intersectionWidth=this.intersectionWidth,i.lateralSurfaceMaterial=this.lateralSurfaceMaterial,i},ui.prototype.merge=function(i){if(!e(i))throw new n("source is required.");this.xHalfAngle=this.xHalfAngle??i.xHalfAngle,this.yHalfAngle=this.yHalfAngle??i.yHalfAngle,this.radius=this.radius??i.radius,this.show=this.show??i.show,this.showIntersection=this.showIntersection??i.showIntersection,this.intersectionColor=this.intersectionColor??i.intersectionColor,this.intersectionWidth=this.intersectionWidth??i.intersectionWidth,this.lateralSurfaceMaterial=this.lateralSurfaceMaterial??i.lateralSurfaceMaterial};const fi=function(i){i=i??r.EMPTY_OBJECT;var t=W(i);t._pickPrimitive=i._pickPrimitive??this,t.directions=void 0,this._customSensor=new L(t),this._xHalfAngle=i.xHalfAngle??k.PI_OVER_TWO,this._yHalfAngle=i.yHalfAngle??k.PI_OVER_TWO,mi(this)};Object.defineProperties(fi.prototype,{xHalfAngle:{get:function(){return this._xHalfAngle},set:function(i){if(i>k.PI_OVER_TWO)throw new n("xHalfAngle must be less than or equal to 90 degrees.");this._xHalfAngle!==i&&(this._xHalfAngle=i,mi(this))}},yHalfAngle:{get:function(){return this._yHalfAngle},set:function(i){if(i>k.PI_OVER_TWO)throw new n("yHalfAngle must be less than or equal to 90 degrees.");this._yHalfAngle!==i&&(this._yHalfAngle=i,mi(this))}},show:{get:function(){return this._customSensor.show},set:function(i){this._customSensor.show=i}},showIntersection:{get:function(){return this._customSensor.showIntersection},set:function(i){this._customSensor.showIntersection=i}},showThroughEllipsoid:{get:function(){return this._customSensor.showThroughEllipsoid},set:function(i){this._customSensor.showThroughEllipsoid=i}},modelMatrix:{get:function(){return this._customSensor.modelMatrix},set:function(i){this._customSensor.modelMatrix=i}},radius:{get:function(){return this._customSensor.radius},set:function(i){this._customSensor.radius=i}},lateralSurfaceMaterial:{get:function(){return this._customSensor.lateralSurfaceMaterial},set:function(i){this._customSensor.lateralSurfaceMaterial=i}},intersectionColor:{get:function(){return this._customSensor.intersectionColor},set:function(i){this._customSensor.intersectionColor=i}},intersectionWidth:{get:function(){return this._customSensor.intersectionWidth},set:function(i){this._customSensor.intersectionWidth=i}},id:{get:function(){return this._customSensor.id},set:function(i){this._customSensor.id=i}}}),fi.prototype.update=function(i){this._customSensor.update(i)},fi.prototype.isDestroyed=function(){return!1},fi.prototype.destroy=function(){return this._customSensor=this._customSensor&&this._customSensor.destroy(),C(this)};const _i=S.WHITE,pi=Number.POSITIVE_INFINITY,Ci=new x,gi=new s,vi=new T,wi=function(i,t){if(!e(i))throw new n("scene is required.");if(!e(t))throw new n("entityCollection is required.");t.collectionChanged.addEventListener(wi.prototype._onCollectionChanged,this),this._scene=i,this._primitives=i.primitives,this._entityCollection=t,this._hash={},this._entitiesToVisualize=new b,this._onCollectionChanged(t,t.values,[],[])};wi.prototype.update=function(i){if(!e(i))throw new n("time is required.");for(var t=this._entitiesToVisualize.values,o=this._hash,r=this._primitives,a=0,l=t.length;a-1;n--)J(i[n],t,e);return C(this)},wi.prototype._onCollectionChanged=function(i,t,n,o){var r,s,a=this._entitiesToVisualize,l=this._hash,h=this._primitives;for(r=t.length-1;r>-1;r--)s=t[r],e(s._rectangularSensor)&&e(s._position)&&e(s._orientation)&&a.set(s.id,s);for(r=o.length-1;r>-1;r--)s=o[r],e(s._rectangularSensor)&&e(s._position)&&e(s._orientation)?a.set(s.id,s):(J(s,l,h),a.remove(s.id));for(r=n.length-1;r>-1;r--)J(s=n[r],l,h),a.remove(s.id)};var Si=P.processPacketData,yi=P.processMaterialPacketData;function Ai(i,t,n,o,r){var a,l,h=[],c=t.unitSpherical,u=t.spherical,d=t.unitCartesian,m=t.cartesian;if(e(c)){for(a=0,l=c.length;a u_sensorRadius)\n {\n discard;\n }\n\n \n bool isOnEllipsoid = isOnBoundary(ellipsoidValue, czm_epsilon3);\n out_FragColor = shade(isOnEllipsoid);\n}\n",N="#version 300 es\n\nin vec4 position;\nin vec3 normal;\n\nout vec3 v_positionWC;\nout vec3 v_positionEC;\nout vec3 v_normalEC;\n\nvoid main()\n{\n gl_Position = czm_modelViewProjection * position;\n v_positionWC = (czm_model * position).xyz;\n v_positionEC = (czm_modelView * position).xyz;\n v_normalEC = czm_normal * normal;\n}\n";const q={position:0,normal:1},B=5906376272e3,L=function(i){i=i??r.EMPTY_OBJECT,this._pickId=void 0,this._pickPrimitive=i._pickPrimitive??this,this._frontFaceColorCommand=new g,this._backFaceColorCommand=new g,this._pickCommand=new g,this._boundingSphere=new m,this._boundingSphereWC=new m,this._frontFaceColorCommand.primitiveType=v.TRIANGLES,this._frontFaceColorCommand.boundingVolume=this._boundingSphereWC,this._frontFaceColorCommand.owner=this,this._backFaceColorCommand.primitiveType=this._frontFaceColorCommand.primitiveType,this._backFaceColorCommand.boundingVolume=this._frontFaceColorCommand.boundingVolume,this._backFaceColorCommand.owner=this,this._pickCommand.primitiveType=this._frontFaceColorCommand.primitiveType,this._pickCommand.boundingVolume=this._frontFaceColorCommand.boundingVolume,this._pickCommand.owner=this,this.show=i.show??!0,this.showIntersection=i.showIntersection??!0,this.showThroughEllipsoid=i.showThroughEllipsoid??!1,this._showThroughEllipsoid=this.showThroughEllipsoid,this.modelMatrix=d.clone(i.modelMatrix??d.IDENTITY),this._modelMatrix=new d,this.radius=i.radius??Number.POSITIVE_INFINITY,this._directions=void 0,this._directionsDirty=!1,this.directions=e(i.directions)?i.directions:[],this.lateralSurfaceMaterial=e(i.lateralSurfaceMaterial)?i.lateralSurfaceMaterial:w.fromType(w.ColorType),this._lateralSurfaceMaterial=void 0,this._translucent=void 0,this.intersectionColor=S.clone(i.intersectionColor??S.WHITE),this.intersectionWidth=i.intersectionWidth??5,this.id=i.id,this._id=void 0;var t=this;this._uniforms={u_showThroughEllipsoid:function(){return t.showThroughEllipsoid},u_showIntersection:function(){return t.showIntersection},u_sensorRadius:function(){return isFinite(t.radius)?t.radius:B},u_intersectionColor:function(){return t.intersectionColor},u_intersectionWidth:function(){return t.intersectionWidth},u_normalDirection:function(){return 1}},this._mode=a.SCENE3D};Object.defineProperties(L.prototype,{directions:{get:function(){return this._directions},set:function(i){this._directions=i,this._directionsDirty=!0}}});const U=new s,Y=new s,j=new s;const Q=new s;function G(i,t){for(var e=function(i){for(var t=i._directions,e=t.length,n=new Float32Array(3*e),o=isFinite(i.radius)?i.radius:B,r=[s.ZERO],a=e-2,l=e-1,h=0;h=3&&(this._frontFaceColorCommand.vertexArray=G(this,t),this._backFaceColorCommand.vertexArray=this._frontFaceColorCommand.vertexArray,this._pickCommand.vertexArray=this._frontFaceColorCommand.vertexArray)}if(e(this._frontFaceColorCommand.vertexArray)){var v=i.passes,w=!d.equals(this.modelMatrix,this._modelMatrix);w&&d.clone(this.modelMatrix,this._modelMatrix),(C||w)&&m.transform(this._boundingSphere,this.modelMatrix,this._boundingSphereWC),this._frontFaceColorCommand.modelMatrix=this.modelMatrix,this._backFaceColorCommand.modelMatrix=this._frontFaceColorCommand.modelMatrix,this._pickCommand.modelMatrix=this._frontFaceColorCommand.modelMatrix;var S=this._lateralSurfaceMaterial!==this.lateralSurfaceMaterial;if(this._lateralSurfaceMaterial=this.lateralSurfaceMaterial,this._lateralSurfaceMaterial.update(t),v.render){var y=this._frontFaceColorCommand,A=this._backFaceColorCommand;if(S||!e(y.shaderProgram)){var M=new f({sources:[D,this._lateralSurfaceMaterial.shaderSource,R]});y.shaderProgram=_.replaceCache({context:t,shaderProgram:y.shaderProgram,vertexShaderSource:N,fragmentShaderSource:M,attributeLocations:q}),y.uniformMap=p(this._uniforms,this._lateralSurfaceMaterial._uniforms),A.shaderProgram=y.shaderProgram,A.uniformMap=p(this._uniforms,this._lateralSurfaceMaterial._uniforms),A.uniformMap.u_normalDirection=function(){return-1}}s?o.push(this._backFaceColorCommand,this._frontFaceColorCommand):o.push(this._frontFaceColorCommand)}if(v.pick){var I=this._pickCommand;if(e(this._pickId)&&this._id===this.id||(this._id=this.id,this._pickId=this._pickId&&this._pickId.destroy(),this._pickId=t.createPickId({primitive:this._pickPrimitive,id:this.id})),S||!e(I.shaderProgram)){var x=new f({sources:[D,this._lateralSurfaceMaterial.shaderSource,R],pickColorQualifier:"uniform"});I.shaderProgram=_.replaceCache({context:t,shaderProgram:I.shaderProgram,vertexShaderSource:N,fragmentShaderSource:x,attributeLocations:q});var T=this,b={czm_pickColor:function(){return T._pickId.color}};I.uniformMap=p(p(this._uniforms,this._lateralSurfaceMaterial._uniforms),b)}I.pass=s?u.TRANSLUCENT:u.OPAQUE,o.push(I)}}}},L.prototype.isDestroyed=function(){return!1},L.prototype.destroy=function(){return this._frontFaceColorCommand.vertexArray=this._frontFaceColorCommand.vertexArray&&this._frontFaceColorCommand.vertexArray.destroy(),this._frontFaceColorCommand.shaderProgram=this._frontFaceColorCommand.shaderProgram&&this._frontFaceColorCommand.shaderProgram.destroy(),this._pickCommand.shaderProgram=this._pickCommand.shaderProgram&&this._pickCommand.shaderProgram.destroy(),this._pickId=this._pickId&&this._pickId.destroy(),C(this)};const K=S.WHITE,Z=Number.POSITIVE_INFINITY,X=new x,$=new s,ii=new T;function ti(i,t,n,o){var r=t[i];e(r)||(r=new V,t[i]=r),r.clock=n,r.cone=o,r.magnitude=1}function ei(i,t,e,n,o){var r,s=i.directions,a=0,l=k.toRadians(2);if(0===t&&e===k.TWO_PI)for(r=0;rt;r-=l)ti(a++,s,r,n);ti(a++,s,t,n)}else ti(a++,s,e,0)}s.length=a,i.directions=s}const ni=function(i,t){if(!e(i))throw new n("scene is required.");if(!e(t))throw new n("entityCollection is required.");t.collectionChanged.addEventListener(ni.prototype._onCollectionChanged,this),this._scene=i,this._primitives=i.primitives,this._entityCollection=t,this._hash={},this._entitiesToVisualize=new b,this._onCollectionChanged(t,t.values,[],[])};ni.prototype.update=function(i){if(!e(i))throw new n("time is required.");for(var t=this._entitiesToVisualize.values,o=this._hash,r=this._primitives,a=0,l=t.length;a-1;n--)J(i[n],t,e);return C(this)},ni.prototype._onCollectionChanged=function(i,t,n,o){var r,s,a=this._entitiesToVisualize,l=this._hash,h=this._primitives;for(r=t.length-1;r>-1;r--)s=t[r],e(s._conicSensor)&&e(s._position)&&e(s._orientation)&&a.set(s.id,s);for(r=o.length-1;r>-1;r--)s=o[r],e(s._conicSensor)&&e(s._position)&&e(s._orientation)?a.set(s.id,s):(J(s,l,h),a.remove(s.id));for(r=n.length-1;r>-1;r--)J(s=n[r],l,h),a.remove(s.id)};const oi=function(i){this._directions=void 0,this._directionsSubscription=void 0,this._lateralSurfaceMaterial=void 0,this._lateralSurfaceMaterialSubscription=void 0,this._intersectionColor=void 0,this._intersectionColorSubscription=void 0,this._intersectionWidth=void 0,this._intersectionWidthSubscription=void 0,this._showIntersection=void 0,this._showIntersectionSubscription=void 0,this._radius=void 0,this._radiusSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._definitionChanged=new o,this.merge(i??r.EMPTY_OBJECT)};Object.defineProperties(oi.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},directions:i("directions"),lateralSurfaceMaterial:t("lateralSurfaceMaterial"),intersectionColor:i("intersectionColor"),intersectionWidth:i("intersectionWidth"),showIntersection:i("showIntersection"),radius:i("radius"),show:i("show")}),oi.prototype.clone=function(i){return e(i)||(i=new oi),i.directions=this.directions,i.radius=this.radius,i.show=this.show,i.showIntersection=this.showIntersection,i.intersectionColor=this.intersectionColor,i.intersectionWidth=this.intersectionWidth,i.lateralSurfaceMaterial=this.lateralSurfaceMaterial,i},oi.prototype.merge=function(i){if(!e(i))throw new n("source is required.");this.directions=this.directions??i.directions,this.radius=this.radius??i.radius,this.show=this.show??i.show,this.showIntersection=this.showIntersection??i.showIntersection,this.intersectionColor=this.intersectionColor??i.intersectionColor,this.intersectionWidth=this.intersectionWidth??i.intersectionWidth,this.lateralSurfaceMaterial=this.lateralSurfaceMaterial??i.lateralSurfaceMaterial};const ri=S.WHITE,si=Number.POSITIVE_INFINITY,ai=new x,li=new s,hi=new T,ci=function(i,t){if(!e(i))throw new n("scene is required.");if(!e(t))throw new n("entityCollection is required.");t.collectionChanged.addEventListener(ci.prototype._onCollectionChanged,this),this._scene=i,this._primitives=i.primitives,this._entityCollection=t,this._hash={},this._entitiesToVisualize=new b,this._onCollectionChanged(t,t.values,[],[])};ci.prototype.update=function(i){if(!e(i))throw new n("time is required.");for(var t=this._entitiesToVisualize.values,o=this._hash,r=this._primitives,a=0,l=t.length;a-1;n--)J(i[n],t,e);return C(this)},ci.prototype._onCollectionChanged=function(i,t,n,o){var r,s,a=this._entitiesToVisualize,l=this._hash,h=this._primitives;for(r=t.length-1;r>-1;r--)s=t[r],e(s._customPatternSensor)&&e(s._position)&&e(s._orientation)&&a.set(s.id,s);for(r=o.length-1;r>-1;r--)s=o[r],e(s._customPatternSensor)&&e(s._position)&&e(s._orientation)?a.set(s.id,s):(J(s,l,h),a.remove(s.id));for(r=n.length-1;r>-1;r--)J(s=n[r],l,h),a.remove(s.id)};const ui=function(){this._xHalfAngle=void 0,this._xHalfAngleSubscription=void 0,this._yHalfAngle=void 0,this._yHalfAngleSubscription=void 0,this._lateralSurfaceMaterial=void 0,this._lateralSurfaceMaterialSubscription=void 0,this._intersectionColor=void 0,this._intersectionColorSubscription=void 0,this._intersectionWidth=void 0,this._intersectionWidthSubscription=void 0,this._showIntersection=void 0,this._showIntersectionSubscription=void 0,this._radius=void 0,this._radiusSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._definitionChanged=new o};function di(i,t,n,o){var r=t[i];e(r)||(r=new V,t[i]=r),r.clock=n,r.cone=o,r.magnitude=1}function mi(i){var t=i._customSensor.directions,e=Math.tan(Math.min(i._xHalfAngle,k.toRadians(89))),n=Math.tan(Math.min(i._yHalfAngle,k.toRadians(89))),o=Math.atan(e/n),r=Math.atan(Math.sqrt(e*e+n*n));di(0,t,o,r),di(1,t,k.toRadians(180)-o,r),di(2,t,k.toRadians(180)+o,r),di(3,t,-o,r),t.length=4,i._customSensor.directions=t}Object.defineProperties(ui.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},xHalfAngle:i("xHalfAngle"),yHalfAngle:i("yHalfAngle"),lateralSurfaceMaterial:i("lateralSurfaceMaterial"),intersectionColor:i("intersectionColor"),intersectionWidth:i("intersectionWidth"),showIntersection:i("showIntersection"),radius:i("radius"),show:i("show")}),ui.prototype.clone=function(i){return e(i)||(i=new ui),i.xHalfAngle=this.xHalfAngle,i.yHalfAngle=this.yHalfAngle,i.radius=this.radius,i.show=this.show,i.showIntersection=this.showIntersection,i.intersectionColor=this.intersectionColor,i.intersectionWidth=this.intersectionWidth,i.lateralSurfaceMaterial=this.lateralSurfaceMaterial,i},ui.prototype.merge=function(i){if(!e(i))throw new n("source is required.");this.xHalfAngle=this.xHalfAngle??i.xHalfAngle,this.yHalfAngle=this.yHalfAngle??i.yHalfAngle,this.radius=this.radius??i.radius,this.show=this.show??i.show,this.showIntersection=this.showIntersection??i.showIntersection,this.intersectionColor=this.intersectionColor??i.intersectionColor,this.intersectionWidth=this.intersectionWidth??i.intersectionWidth,this.lateralSurfaceMaterial=this.lateralSurfaceMaterial??i.lateralSurfaceMaterial};const fi=function(i){i=i??r.EMPTY_OBJECT;var t=W(i);t._pickPrimitive=i._pickPrimitive??this,t.directions=void 0,this._customSensor=new L(t),this._xHalfAngle=i.xHalfAngle??k.PI_OVER_TWO,this._yHalfAngle=i.yHalfAngle??k.PI_OVER_TWO,mi(this)};Object.defineProperties(fi.prototype,{xHalfAngle:{get:function(){return this._xHalfAngle},set:function(i){if(i>k.PI_OVER_TWO)throw new n("xHalfAngle must be less than or equal to 90 degrees.");this._xHalfAngle!==i&&(this._xHalfAngle=i,mi(this))}},yHalfAngle:{get:function(){return this._yHalfAngle},set:function(i){if(i>k.PI_OVER_TWO)throw new n("yHalfAngle must be less than or equal to 90 degrees.");this._yHalfAngle!==i&&(this._yHalfAngle=i,mi(this))}},show:{get:function(){return this._customSensor.show},set:function(i){this._customSensor.show=i}},showIntersection:{get:function(){return this._customSensor.showIntersection},set:function(i){this._customSensor.showIntersection=i}},showThroughEllipsoid:{get:function(){return this._customSensor.showThroughEllipsoid},set:function(i){this._customSensor.showThroughEllipsoid=i}},modelMatrix:{get:function(){return this._customSensor.modelMatrix},set:function(i){this._customSensor.modelMatrix=i}},radius:{get:function(){return this._customSensor.radius},set:function(i){this._customSensor.radius=i}},lateralSurfaceMaterial:{get:function(){return this._customSensor.lateralSurfaceMaterial},set:function(i){this._customSensor.lateralSurfaceMaterial=i}},intersectionColor:{get:function(){return this._customSensor.intersectionColor},set:function(i){this._customSensor.intersectionColor=i}},intersectionWidth:{get:function(){return this._customSensor.intersectionWidth},set:function(i){this._customSensor.intersectionWidth=i}},id:{get:function(){return this._customSensor.id},set:function(i){this._customSensor.id=i}}}),fi.prototype.update=function(i){this._customSensor.update(i)},fi.prototype.isDestroyed=function(){return!1},fi.prototype.destroy=function(){return this._customSensor=this._customSensor&&this._customSensor.destroy(),C(this)};const _i=S.WHITE,pi=Number.POSITIVE_INFINITY,Ci=new x,gi=new s,vi=new T,wi=function(i,t){if(!e(i))throw new n("scene is required.");if(!e(t))throw new n("entityCollection is required.");t.collectionChanged.addEventListener(wi.prototype._onCollectionChanged,this),this._scene=i,this._primitives=i.primitives,this._entityCollection=t,this._hash={},this._entitiesToVisualize=new b,this._onCollectionChanged(t,t.values,[],[])};wi.prototype.update=function(i){if(!e(i))throw new n("time is required.");for(var t=this._entitiesToVisualize.values,o=this._hash,r=this._primitives,a=0,l=t.length;a-1;n--)J(i[n],t,e);return C(this)},wi.prototype._onCollectionChanged=function(i,t,n,o){var r,s,a=this._entitiesToVisualize,l=this._hash,h=this._primitives;for(r=t.length-1;r>-1;r--)s=t[r],e(s._rectangularSensor)&&e(s._position)&&e(s._orientation)&&a.set(s.id,s);for(r=o.length-1;r>-1;r--)s=o[r],e(s._rectangularSensor)&&e(s._position)&&e(s._orientation)?a.set(s.id,s):(J(s,l,h),a.remove(s.id));for(r=n.length-1;r>-1;r--)J(s=n[r],l,h),a.remove(s.id)};var Si=P.processPacketData,yi=P.processMaterialPacketData;function Ai(i,t,n,o,r){var a,l,h=[],c=t.unitSpherical,u=t.spherical,d=t.unitCartesian,m=t.cartesian;if(e(c)){for(a=0,l=c.length;a