/** * Cesium Sensor Volumes - https://github.com/jlouns/cesium-sensor-volumes * * Copyright 2016 Jonathan Lounsbury * Copyright 2011-2014 Analytical Graphics Inc. and Cesium Contributors * * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. * * Portions licensed separately. * See https://github.com/jlouns/cesium-sensor-volumes/blob/master/LICENSE.md for full licensing details. * * Derived from Cesium Sensors - https://github.com/AnalyticalGraphicsInc/cesium-sensors */ (function () { /** * @license almond 0.3.3 Copyright jQuery Foundation and other contributors. * Released under MIT license, http://github.com/requirejs/almond/LICENSE */ //Going sloppy to avoid 'use strict' string cost, but strict practices should //be followed. /*global setTimeout: false */ var requirejs, require, define; (function (undef) { var main, req, makeMap, handlers, defined = {}, waiting = {}, config = {}, defining = {}, hasOwn = Object.prototype.hasOwnProperty, aps = [].slice, jsSuffixRegExp = /\.js$/; function hasProp(obj, prop) { return hasOwn.call(obj, prop); } /** * Given a relative module name, like ./something, normalize it to * a real name that can be mapped to a path. * @param {String} name the relative name * @param {String} baseName a real name that the name arg is relative * to. * @returns {String} normalized name */ function normalize(name, baseName) { var nameParts, nameSegment, mapValue, foundMap, lastIndex, foundI, foundStarMap, starI, i, j, part, normalizedBaseParts, baseParts = baseName && baseName.split("/"), map = config.map, starMap = (map && map["*"]) || {}; //Adjust any relative paths. if (name) { name = name.split("/"); lastIndex = name.length - 1; // If wanting node ID compatibility, strip .js from end // of IDs. Have to do this here, and not in nameToUrl // because node allows either .js or non .js to map // to same file. if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ""); } // Starts with a '.' so need the baseName if (name[0].charAt(0) === "." && baseParts) { //Convert baseName to array, and lop off the last part, //so that . matches that 'directory' and not name of the baseName's //module. For instance, baseName of 'one/two/three', maps to //'one/two/three.js', but we want the directory, 'one/two' for //this normalization. normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); name = normalizedBaseParts.concat(name); } //start trimDots for (i = 0; i < name.length; i++) { part = name[i]; if (part === ".") { name.splice(i, 1); i -= 1; } else if (part === "..") { // If at the start, or previous value is still .., // keep them so that when converted to a path it may // still work when converted to a path, even though // as an ID it is less than ideal. In larger point // releases, may be better to just kick out an error. if ( i === 0 || (i === 1 && name[2] === "..") || name[i - 1] === ".." ) { continue; } else if (i > 0) { name.splice(i - 1, 2); i -= 2; } } } //end trimDots name = name.join("/"); } //Apply map config if available. if ((baseParts || starMap) && map) { nameParts = name.split("/"); for (i = nameParts.length; i > 0; i -= 1) { nameSegment = nameParts.slice(0, i).join("/"); if (baseParts) { //Find the longest baseName segment match in the config. //So, do joins on the biggest to smallest lengths of baseParts. for (j = baseParts.length; j > 0; j -= 1) { mapValue = map[baseParts.slice(0, j).join("/")]; //baseName segment has config, find if it has one for //this name. if (mapValue) { mapValue = mapValue[nameSegment]; if (mapValue) { //Match, update name to the new value. foundMap = mapValue; foundI = i; break; } } } } if (foundMap) { break; } //Check for a star map match, but just hold on to it, //if there is a shorter segment match later in a matching //config, then favor over this star map. if (!foundStarMap && starMap && starMap[nameSegment]) { foundStarMap = starMap[nameSegment]; starI = i; } } if (!foundMap && foundStarMap) { foundMap = foundStarMap; foundI = starI; } if (foundMap) { nameParts.splice(0, foundI, foundMap); name = nameParts.join("/"); } } return name; } function makeRequire(relName, forceSync) { return function () { //A version of a require function that passes a moduleName //value for items that may need to //look up paths relative to the moduleName var args = aps.call(arguments, 0); //If first arg is not require('string'), and there is only //one arg, it is the array form without a callback. Insert //a null so that the following concat is correct. if (typeof args[0] !== "string" && args.length === 1) { args.push(null); } return req.apply(undef, args.concat([relName, forceSync])); }; } function makeNormalize(relName) { return function (name) { return normalize(name, relName); }; } function makeLoad(depName) { return function (value) { defined[depName] = value; }; } function callDep(name) { if (hasProp(waiting, name)) { var args = waiting[name]; delete waiting[name]; defining[name] = true; main.apply(undef, args); } if (!hasProp(defined, name) && !hasProp(defining, name)) { throw new Error("No " + name); } return defined[name]; } //Turns a plugin!resource to [plugin, resource] //with the plugin being undefined if the name //did not have a plugin prefix. function splitPrefix(name) { var prefix, index = name ? name.indexOf("!") : -1; if (index > -1) { prefix = name.substring(0, index); name = name.substring(index + 1, name.length); } return [prefix, name]; } //Creates a parts array for a relName where first part is plugin ID, //second part is resource ID. Assumes relName has already been normalized. function makeRelParts(relName) { return relName ? splitPrefix(relName) : []; } /** * Makes a name map, normalizing the name, and using a plugin * for normalization if necessary. Grabs a ref to plugin * too, as an optimization. */ makeMap = function (name, relParts) { var plugin, parts = splitPrefix(name), prefix = parts[0], relResourceName = relParts[1]; name = parts[1]; if (prefix) { prefix = normalize(prefix, relResourceName); plugin = callDep(prefix); } //Normalize according if (prefix) { if (plugin && plugin.normalize) { name = plugin.normalize(name, makeNormalize(relResourceName)); } else { name = normalize(name, relResourceName); } } else { name = normalize(name, relResourceName); parts = splitPrefix(name); prefix = parts[0]; name = parts[1]; if (prefix) { plugin = callDep(prefix); } } //Using ridiculous property names for space reasons return { f: prefix ? prefix + "!" + name : name, //fullName n: name, pr: prefix, p: plugin, }; }; function makeConfig(name) { return function () { return (config && config.config && config.config[name]) || {}; }; } handlers = { require: function (name) { return makeRequire(name); }, exports: function (name) { var e = defined[name]; if (typeof e !== "undefined") { return e; } else { return (defined[name] = {}); } }, module: function (name) { return { id: name, uri: "", exports: defined[name], config: makeConfig(name), }; }, }; main = function (name, deps, callback, relName) { var cjsModule, depName, ret, map, i, relParts, args = [], callbackType = typeof callback, usingExports; //Use name if no relName relName = relName || name; relParts = makeRelParts(relName); //Call the callback to define the module, if necessary. if (callbackType === "undefined" || callbackType === "function") { //Pull out the defined dependencies and pass the ordered //values to the callback. //Default to [require, exports, module] if no deps deps = !deps.length && callback.length ? ["require", "exports", "module"] : deps; for (i = 0; i < deps.length; i += 1) { map = makeMap(deps[i], relParts); depName = map.f; //Fast path CommonJS standard dependencies. if (depName === "require") { args[i] = handlers.require(name); } else if (depName === "exports") { //CommonJS module spec 1.1 args[i] = handlers.exports(name); usingExports = true; } else if (depName === "module") { //CommonJS module spec 1.1 cjsModule = args[i] = handlers.module(name); } else if ( hasProp(defined, depName) || hasProp(waiting, depName) || hasProp(defining, depName) ) { args[i] = callDep(depName); } else if (map.p) { map.p.load( map.n, makeRequire(relName, true), makeLoad(depName), {} ); args[i] = defined[depName]; } else { throw new Error(name + " missing " + depName); } } ret = callback ? callback.apply(defined[name], args) : undefined; if (name) { //If setting exports via "module" is in play, //favor that over return value and exports. After that, //favor a non-undefined return value over exports use. if ( cjsModule && cjsModule.exports !== undef && cjsModule.exports !== defined[name] ) { defined[name] = cjsModule.exports; } else if (ret !== undef || !usingExports) { //Use the return value from the function. defined[name] = ret; } } } else if (name) { //May just be an object definition for the module. Only //worry about defining if have a module name. defined[name] = callback; } }; requirejs = require = req = function (deps, callback, relName, forceSync, alt) { if (typeof deps === "string") { if (handlers[deps]) { //callback in this case is really relName return handlers[deps](callback); } //Just return the module wanted. In this scenario, the //deps arg is the module name, and second arg (if passed) //is just the relName. //Normalize module name, if it contains . or .. return callDep(makeMap(deps, makeRelParts(callback)).f); } else if (!deps.splice) { //deps is a config object, not an array. config = deps; if (config.deps) { req(config.deps, config.callback); } if (!callback) { return; } if (callback.splice) { //callback is an array, which means it is a dependency list. //Adjust args if there are dependencies deps = callback; callback = relName; relName = null; } else { deps = undef; } } //Support require(['a']) callback = callback || function () {}; //If relName is a function, it is an errback handler, //so remove it. if (typeof relName === "function") { relName = forceSync; forceSync = alt; } //Simulate async callback; if (forceSync) { main(undef, deps, callback, relName); } else { //Using a non-zero value because of concern for what old browsers //do, and latest browsers "upgrade" to 4 if lower value is used: //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: //If want a value immediately, use require('id') instead -- something //that works in almond on the global level, but not guaranteed and //unlikely to work in other AMD implementations. setTimeout(function () { main(undef, deps, callback, relName); }, 4); } return req; }; /** * Just drops the config on the floor, but returns req in case * the config return value is used. */ req.config = function (cfg) { return req(cfg); }; /** * Expose module registry for debugging and tooling */ requirejs._defined = defined; define = function (name, deps, callback) { if (typeof name !== "string") { throw new Error( "See almond README: incorrect module build, no module name" ); } //This module may not have dependencies if (!deps.splice) { //deps is not an array, so probably means //an object literal or factory function for //the value. Adjust args. callback = deps; deps = []; } if (!hasProp(defined, name) && !hasProp(waiting, name)) { waiting[name] = [name, deps, callback]; } }; define.amd = { jQuery: true, }; })(); define("conic/conic-sensor-graphics", [ "require", "Cesium/Core/defaultValue", "Cesium/Core/defined", "Cesium/Core/DeveloperError", "Cesium/Core/Event", "Cesium/DataSources/createMaterialPropertyDescriptor", "Cesium/DataSources/createPropertyDescriptor", ], function (require) { "use strict"; var defaultValue = require("Cesium/Core/defaultValue"); var defined = require("Cesium/Core/defined"); var defineProperties = Object.defineProperties; var DeveloperError = require("Cesium/Core/DeveloperError"); var Event = require("Cesium/Core/Event"); var createMaterialPropertyDescriptor = require("Cesium/DataSources/createMaterialPropertyDescriptor"); var createPropertyDescriptor = require("Cesium/DataSources/createPropertyDescriptor"); /** * An optionally time-dynamic cone. * * @alias ConicSensorGraphics * @constructor */ var ConicSensorGraphics = function (options) { this._minimumClockAngle = undefined; this._minimumClockAngleSubscription = undefined; this._maximumClockAngle = undefined; this._maximumClockAngleSubscription = undefined; this._innerHalfAngle = undefined; this._innerHalfAngleSubscription = undefined; this._outerHalfAngle = undefined; this._outerHalfAngleSubscription = undefined; this._lateralSurfaceMaterial = undefined; this._lateralSurfaceMaterialSubscription = undefined; this._intersectionColor = undefined; this._intersectionColorSubscription = undefined; this._intersectionWidth = undefined; this._intersectionWidthSubscription = undefined; this._showIntersection = undefined; this._showIntersectionSubscription = undefined; this._radius = undefined; this._radiusSubscription = undefined; this._show = undefined; this._showSubscription = undefined; this._definitionChanged = new Event(); this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT)); }; defineProperties(ConicSensorGraphics.prototype, { /** * Gets the event that is raised whenever a new property is assigned. * @memberof ConicSensorGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function () { return this._definitionChanged; }, }, /** * Gets or sets the numeric {@link Property} specifying the the cone's minimum clock angle. * @memberof ConicSensorGraphics.prototype * @type {Property} */ minimumClockAngle: createPropertyDescriptor("minimumClockAngle"), /** * Gets or sets the numeric {@link Property} specifying the the cone's maximum clock angle. * @memberof ConicSensorGraphics.prototype * @type {Property} */ maximumClockAngle: createPropertyDescriptor("maximumClockAngle"), /** * Gets or sets the numeric {@link Property} specifying the the cone's inner half-angle. * @memberof ConicSensorGraphics.prototype * @type {Property} */ innerHalfAngle: createPropertyDescriptor("innerHalfAngle"), /** * Gets or sets the numeric {@link Property} specifying the the cone's outer half-angle. * @memberof ConicSensorGraphics.prototype * @type {Property} */ outerHalfAngle: createPropertyDescriptor("outerHalfAngle"), /** * Gets or sets the {@link MaterialProperty} specifying the the cone's appearance. * @memberof ConicSensorGraphics.prototype * @type {MaterialProperty} */ lateralSurfaceMaterial: createMaterialPropertyDescriptor( "lateralSurfaceMaterial" ), /** * 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. * @memberof ConicSensorGraphics.prototype * @type {Property} */ intersectionColor: createPropertyDescriptor("intersectionColor"), /** * Gets or sets the numeric {@link Property} specifying the width of the line formed by the intersection of the cone and other central bodies. * @memberof ConicSensorGraphics.prototype * @type {Property} */ intersectionWidth: createPropertyDescriptor("intersectionWidth"), /** * Gets or sets the boolean {@link Property} specifying the visibility of the line formed by the intersection of the cone and other central bodies. * @memberof ConicSensorGraphics.prototype * @type {Property} */ showIntersection: createPropertyDescriptor("showIntersection"), /** * Gets or sets the numeric {@link Property} specifying the radius of the cone's projection. * @memberof ConicSensorGraphics.prototype * @type {Property} */ radius: createPropertyDescriptor("radius"), /** * Gets or sets the boolean {@link Property} specifying the visibility of the cone. * @memberof ConicSensorGraphics.prototype * @type {Property} */ show: createPropertyDescriptor("show"), }); /** * Duplicates a ConicSensorGraphics instance. * * @param {ConicSensorGraphics} [result] The object onto which to store the result. * @returns {ConicSensorGraphics} The modified result parameter or a new instance if one was not provided. */ ConicSensorGraphics.prototype.clone = function (result) { if (!defined(result)) { result = new ConicSensorGraphics(); } result.show = this.show; result.innerHalfAngle = this.innerHalfAngle; result.outerHalfAngle = this.outerHalfAngle; result.minimumClockAngle = this.minimumClockAngle; result.maximumClockAngle = this.maximumClockAngle; result.radius = this.radius; result.showIntersection = this.showIntersection; result.intersectionColor = this.intersectionColor; result.intersectionWidth = this.intersectionWidth; result.lateralSurfaceMaterial = this.lateralSurfaceMaterial; return result; }; /** * Assigns each unassigned property on this object to the value * of the same property on the provided source object. * * @param {ConicSensorGraphics} source The object to be merged into this object. */ ConicSensorGraphics.prototype.merge = function (source) { // >>includeStart('debug', pragmas.debug); if (!defined(source)) { throw new DeveloperError("source is required."); } // >>includeEnd('debug'); this.show = defaultValue(this.show, source.show); this.innerHalfAngle = defaultValue( this.innerHalfAngle, source.innerHalfAngle ); this.outerHalfAngle = defaultValue( this.outerHalfAngle, source.outerHalfAngle ); this.minimumClockAngle = defaultValue( this.minimumClockAngle, source.minimumClockAngle ); this.maximumClockAngle = defaultValue( this.maximumClockAngle, source.maximumClockAngle ); this.radius = defaultValue(this.radius, source.radius); this.showIntersection = defaultValue( this.showIntersection, source.showIntersection ); this.intersectionColor = defaultValue( this.intersectionColor, source.intersectionColor ); this.intersectionWidth = defaultValue( this.intersectionWidth, source.intersectionWidth ); this.lateralSurfaceMaterial = defaultValue( this.lateralSurfaceMaterial, source.lateralSurfaceMaterial ); }; return ConicSensorGraphics; }); define("text", { load: function (id) { throw new Error("Dynamic load not allowed: " + id); }, }); define("text!custom/custom-sensor-volume-fs.glsl", [], function () { return "#ifdef GL_OES_standard_derivatives\n#extension GL_OES_standard_derivatives : enable\n#endif\nuniform bool u_showIntersection;\nuniform bool u_showThroughEllipsoid;\nuniform float u_sensorRadius;\nuniform float u_normalDirection;\nvarying vec3 v_positionWC;\nvarying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvec4 getColor(float sensorRadius, vec3 pointEC)\n{\nczm_materialInput materialInput;\nvec3 pointMC = (czm_inverseModelView * vec4(pointEC, 1.0)).xyz;\nmaterialInput.st = sensor2dTextureCoordinates(sensorRadius, pointMC);\nmaterialInput.str = pointMC / sensorRadius;\nvec3 positionToEyeEC = -v_positionEC;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nvec3 normalEC = normalize(v_normalEC);\nmaterialInput.normalEC = u_normalDirection * normalEC;\nczm_material material = czm_getMaterial(materialInput);\nreturn mix(czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC), vec4(material.diffuse, material.alpha), 0.4);\n}\nbool isOnBoundary(float value, float epsilon)\n{\nfloat width = getIntersectionWidth();\nfloat tolerance = width * epsilon;\n#ifdef GL_OES_standard_derivatives\nfloat delta = max(abs(dFdx(value)), abs(dFdy(value)));\nfloat pixels = width * delta;\nfloat temp = abs(value);\nreturn temp < tolerance && temp < pixels || (delta < 10.0 * tolerance && temp - delta < tolerance && temp < pixels);\n#else\nreturn abs(value) < tolerance;\n#endif\n}\nvec4 shade(bool isOnBoundary)\n{\nif (u_showIntersection && isOnBoundary)\n{\nreturn getIntersectionColor();\n}\nreturn getColor(u_sensorRadius, v_positionEC);\n}\nfloat ellipsoidSurfaceFunction( vec3 point)\n{\nvec3 scaled = czm_ellipsoidInverseRadii * point;\nreturn dot(scaled, scaled) - 1.0;\n}\nvoid main()\n{\nvec3 sensorVertexWC = czm_model[3].xyz;\nvec3 sensorVertexEC = czm_modelView[3].xyz;\nfloat ellipsoidValue = ellipsoidSurfaceFunction( v_positionWC);\nif (!u_showThroughEllipsoid)\n{\nif (ellipsoidValue < 0.0)\n{\ndiscard;\n}\nif (inSensorShadow(sensorVertexWC, v_positionWC))\n{\ndiscard;\n}\n}\nif (distance(v_positionEC, sensorVertexEC) > u_sensorRadius)\n{\ndiscard;\n}\nbool isOnEllipsoid = isOnBoundary(ellipsoidValue, czm_epsilon3);\ngl_FragColor = shade(isOnEllipsoid);\n}"; }); define("text!custom/custom-sensor-volume-vs.glsl", [], function () { return "attribute vec4 position;\nattribute vec3 normal;\nvarying vec3 v_positionWC;\nvarying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvoid main()\n{\ngl_Position = czm_modelViewProjection * position;\nv_positionWC = (czm_model * position).xyz;\nv_positionEC = (czm_modelView * position).xyz;\nv_normalEC = czm_normal * normal;\n}"; }); define("text!sensor-volume.glsl", [], function () { return "uniform vec4 u_intersectionColor;\nuniform float u_intersectionWidth;\nbool inSensorShadow(vec3 coneVertexWC, vec3 pointWC)\n{\nvec3 D = czm_ellipsoidInverseRadii;\nvec3 q = D * coneVertexWC;\nfloat qMagnitudeSquared = dot(q, q);\nfloat test = qMagnitudeSquared - 1.0;\nvec3 temp = D * pointWC - q;\nfloat d = dot(temp, q);\nreturn (d < -test) && (d / length(temp) < -sqrt(test));\n}\nvec4 getIntersectionColor()\n{\nreturn u_intersectionColor;\n}\nfloat getIntersectionWidth()\n{\nreturn u_intersectionWidth;\n}\nvec2 sensor2dTextureCoordinates(float sensorRadius, vec3 pointMC)\n{\nfloat t = pointMC.z / sensorRadius;\nfloat s = 1.0 + (atan(pointMC.y, pointMC.x) / czm_twoPi);\ns = s - floor(s);\nreturn vec2(s, t);\n}"; }); define("custom/custom-sensor-volume", [ "require", "Cesium/Core/BoundingSphere", "Cesium/Core/Cartesian3", "Cesium/Core/Color", "Cesium/Core/combine", "Cesium/Core/ComponentDatatype", "Cesium/Core/defaultValue", "Cesium/Core/defined", "Cesium/Core/destroyObject", "Cesium/Core/DeveloperError", "Cesium/Core/Matrix4", "Cesium/Core/PrimitiveType", "Cesium/Renderer/Buffer", "Cesium/Renderer/BufferUsage", "Cesium/Renderer/DrawCommand", "Cesium/Renderer/Pass", "Cesium/Renderer/RenderState", "Cesium/Renderer/ShaderProgram", "Cesium/Renderer/ShaderSource", "Cesium/Renderer/VertexArray", "Cesium/Scene/BlendingState", "Cesium/Scene/CullFace", "Cesium/Scene/Material", "Cesium/Scene/SceneMode", "text!./custom-sensor-volume-fs.glsl", "text!./custom-sensor-volume-vs.glsl", "text!../sensor-volume.glsl", ], function (require) { "use strict"; var BoundingSphere = require("Cesium/Core/BoundingSphere"); var Cartesian3 = require("Cesium/Core/Cartesian3"); var Color = require("Cesium/Core/Color"); var combine = require("Cesium/Core/combine"); var ComponentDatatype = require("Cesium/Core/ComponentDatatype"); var defaultValue = require("Cesium/Core/defaultValue"); var defined = require("Cesium/Core/defined"); var defineProperties = Object.defineProperties; var destroyObject = require("Cesium/Core/destroyObject"); var DeveloperError = require("Cesium/Core/DeveloperError"); var Matrix4 = require("Cesium/Core/Matrix4"); var PrimitiveType = require("Cesium/Core/PrimitiveType"); var Buffer = require("Cesium/Renderer/Buffer"); var BufferUsage = require("Cesium/Renderer/BufferUsage"); var DrawCommand = require("Cesium/Renderer/DrawCommand"); var Pass = require("Cesium/Renderer/Pass"); var RenderState = require("Cesium/Renderer/RenderState"); var ShaderProgram = require("Cesium/Renderer/ShaderProgram"); var ShaderSource = require("Cesium/Renderer/ShaderSource"); var VertexArray = require("Cesium/Renderer/VertexArray"); var BlendingState = require("Cesium/Scene/BlendingState"); var CullFace = require("Cesium/Scene/CullFace"); var Material = require("Cesium/Scene/Material"); var SceneMode = require("Cesium/Scene/SceneMode"); var CustomSensorVolumeFS = require("text!./custom-sensor-volume-fs.glsl"); var CustomSensorVolumeVS = require("text!./custom-sensor-volume-vs.glsl"); var SensorVolume = require("text!../sensor-volume.glsl"); var attributeLocations = { position: 0, normal: 1, }; var FAR = 5906376272000.0; // distance from the Sun to Pluto in meters. /** * DOC_TBA * * @alias CustomSensorVolume * @constructor */ var CustomSensorVolume = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); this._pickId = undefined; this._pickPrimitive = defaultValue(options._pickPrimitive, this); this._frontFaceColorCommand = new DrawCommand(); this._backFaceColorCommand = new DrawCommand(); this._pickCommand = new DrawCommand(); this._boundingSphere = new BoundingSphere(); this._boundingSphereWC = new BoundingSphere(); this._frontFaceColorCommand.primitiveType = PrimitiveType.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; /** * true if this sensor will be shown; otherwise, false * * @type {Boolean} * @default true */ this.show = defaultValue(options.show, true); /** * When true, a polyline is shown where the sensor outline intersections the globe. * * @type {Boolean} * * @default true * * @see CustomSensorVolume#intersectionColor */ this.showIntersection = defaultValue(options.showIntersection, true); /** *

* Determines if a sensor intersecting the ellipsoid is drawn through the ellipsoid and potentially out * to the other side, or if the part of the sensor intersecting the ellipsoid stops at the ellipsoid. *

* * @type {Boolean} * @default false */ this.showThroughEllipsoid = defaultValue( options.showThroughEllipsoid, false ); this._showThroughEllipsoid = this.showThroughEllipsoid; /** * The 4x4 transformation matrix that transforms this sensor from model to world coordinates. In it's model * coordinates, the sensor's principal direction is along the positive z-axis. The clock angle, sometimes * called azimuth, is the angle in the sensor's X-Y plane measured from the positive X-axis toward the positive * Y-axis. The cone angle, sometimes called elevation, is the angle out of the X-Y plane along the positive Z-axis. *

*
*
* Model coordinate system for a custom sensor *
* * @type {Matrix4} * @default {@link Matrix4.IDENTITY} * * @example * // The sensor's vertex is located on the surface at -75.59777 degrees longitude and 40.03883 degrees latitude. * // The sensor's opens upward, along the surface normal. * var center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883); * sensor.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center); */ this.modelMatrix = Matrix4.clone( defaultValue(options.modelMatrix, Matrix4.IDENTITY) ); this._modelMatrix = new Matrix4(); /** * DOC_TBA * * @type {Number} * @default {@link Number.POSITIVE_INFINITY} */ this.radius = defaultValue(options.radius, Number.POSITIVE_INFINITY); this._directions = undefined; this._directionsDirty = false; this.directions = defined(options.directions) ? options.directions : []; /** * The surface appearance of the sensor. This can be one of several built-in {@link Material} objects or a custom material, scripted with * {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}. *

* The default material is Material.ColorType. *

* * @type {Material} * @default Material.fromType(Material.ColorType) * * @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric} * * @example * // 1. Change the color of the default material to yellow * sensor.lateralSurfaceMaterial.uniforms.color = new Cesium.Color(1.0, 1.0, 0.0, 1.0); * * // 2. Change material to horizontal stripes * sensor.lateralSurfaceMaterial = Cesium.Material.fromType(Material.StripeType); */ this.lateralSurfaceMaterial = defined(options.lateralSurfaceMaterial) ? options.lateralSurfaceMaterial : Material.fromType(Material.ColorType); this._lateralSurfaceMaterial = undefined; this._translucent = undefined; /** * The color of the polyline where the sensor outline intersects the globe. The default is {@link Color.WHITE}. * * @type {Color} * @default {@link Color.WHITE} * * @see CustomSensorVolume#showIntersection */ this.intersectionColor = Color.clone( defaultValue(options.intersectionColor, Color.WHITE) ); /** * The approximate pixel width of the polyline where the sensor outline intersects the globe. The default is 5.0. * * @type {Number} * @default 5.0 * * @see CustomSensorVolume#showIntersection */ this.intersectionWidth = defaultValue(options.intersectionWidth, 5.0); /** * User-defined object returned when the sensors is picked. * * @type Object * * @default undefined * * @see Scene#pick */ this.id = options.id; this._id = undefined; var that = this; /* eslint-disable camelcase */ this._uniforms = { u_showThroughEllipsoid: function () { return that.showThroughEllipsoid; }, u_showIntersection: function () { return that.showIntersection; }, u_sensorRadius: function () { return isFinite(that.radius) ? that.radius : FAR; }, u_intersectionColor: function () { return that.intersectionColor; }, u_intersectionWidth: function () { return that.intersectionWidth; }, u_normalDirection: function () { return 1.0; }, }; /* eslint-enable camelcase */ this._mode = SceneMode.SCENE3D; }; defineProperties(CustomSensorVolume.prototype, { directions: { get: function () { return this._directions; }, set: function (value) { this._directions = value; this._directionsDirty = true; }, }, }); var n0Scratch = new Cartesian3(); var n1Scratch = new Cartesian3(); var n2Scratch = new Cartesian3(); function computePositions(customSensorVolume) { var directions = customSensorVolume._directions; var length = directions.length; var positions = new Float32Array(3 * length); var r = isFinite(customSensorVolume.radius) ? customSensorVolume.radius : FAR; var boundingVolumePositions = [Cartesian3.ZERO]; for ( var i = length - 2, j = length - 1, k = 0; k < length; i = j++, j = k++ ) { // PERFORMANCE_IDEA: We can avoid redundant operations for adjacent edges. var n0 = Cartesian3.fromSpherical(directions[i], n0Scratch); var n1 = Cartesian3.fromSpherical(directions[j], n1Scratch); var n2 = Cartesian3.fromSpherical(directions[k], n2Scratch); // Extend position so the volume encompasses the sensor's radius. var theta = Math.max( Cartesian3.angleBetween(n0, n1), Cartesian3.angleBetween(n1, n2) ); var distance = r / Math.cos(theta * 0.5); var p = Cartesian3.multiplyByScalar(n1, distance, new Cartesian3()); positions[j * 3] = p.x; positions[j * 3 + 1] = p.y; positions[j * 3 + 2] = p.z; boundingVolumePositions.push(p); } BoundingSphere.fromPoints( boundingVolumePositions, customSensorVolume._boundingSphere ); return positions; } var nScratch = new Cartesian3(); function createVertexArray(customSensorVolume, context) { var positions = computePositions(customSensorVolume); var length = customSensorVolume._directions.length; var vertices = new Float32Array(2 * 3 * 3 * length); var k = 0; for (var i = length - 1, j = 0; j < length; i = j++) { var p0 = new Cartesian3( positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2] ); var p1 = new Cartesian3( positions[j * 3], positions[j * 3 + 1], positions[j * 3 + 2] ); var n = Cartesian3.normalize( Cartesian3.cross(p1, p0, nScratch), nScratch ); // Per-face normals vertices[k++] = 0.0; // Sensor vertex vertices[k++] = 0.0; vertices[k++] = 0.0; vertices[k++] = n.x; vertices[k++] = n.y; vertices[k++] = n.z; vertices[k++] = p1.x; vertices[k++] = p1.y; vertices[k++] = p1.z; vertices[k++] = n.x; vertices[k++] = n.y; vertices[k++] = n.z; vertices[k++] = p0.x; vertices[k++] = p0.y; vertices[k++] = p0.z; vertices[k++] = n.x; vertices[k++] = n.y; vertices[k++] = n.z; } var vertexBuffer = Buffer.createVertexBuffer({ context: context, typedArray: new Float32Array(vertices), usage: BufferUsage.STATIC_DRAW, }); var stride = 2 * 3 * Float32Array.BYTES_PER_ELEMENT; var attributes = [ { index: attributeLocations.position, vertexBuffer: vertexBuffer, componentsPerAttribute: 3, componentDatatype: ComponentDatatype.FLOAT, offsetInBytes: 0, strideInBytes: stride, }, { index: attributeLocations.normal, vertexBuffer: vertexBuffer, componentsPerAttribute: 3, componentDatatype: ComponentDatatype.FLOAT, offsetInBytes: 3 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: stride, }, ]; return new VertexArray({ context: context, attributes: attributes, }); } /** * Called when {@link Viewer} or {@link CesiumWidget} render the scene to * get the draw commands needed to render this primitive. *

* Do not call this function directly. This is documented just to * list the exceptions that may be propagated when the scene is rendered: *

* * @exception {DeveloperError} this.radius must be greater than or equal to zero. * @exception {DeveloperError} this.lateralSurfaceMaterial must be defined. */ CustomSensorVolume.prototype.update = function (frameState) { this._mode = frameState.mode; if (!this.show || this._mode !== SceneMode.SCENE3D) { return; } var context = frameState.context; var commandList = frameState.commandList; // >>includeStart('debug', pragmas.debug); if (this.radius < 0.0) { throw new DeveloperError( "this.radius must be greater than or equal to zero." ); } if (!defined(this.lateralSurfaceMaterial)) { throw new DeveloperError( "this.lateralSurfaceMaterial must be defined." ); } // >>includeEnd('debug'); var translucent = this.lateralSurfaceMaterial.isTranslucent(); // Initial render state creation if ( this._showThroughEllipsoid !== this.showThroughEllipsoid || !defined(this._frontFaceColorCommand.renderState) || this._translucent !== translucent ) { this._showThroughEllipsoid = this.showThroughEllipsoid; this._translucent = translucent; var rs; if (translucent) { rs = RenderState.fromCache({ depthTest: { // This would be better served by depth testing with a depth buffer that does not // include the ellipsoid depth - or a g-buffer containing an ellipsoid mask // so we can selectively depth test. enabled: !this.showThroughEllipsoid, }, depthMask: false, blending: BlendingState.ALPHA_BLEND, cull: { enabled: true, face: CullFace.BACK, }, }); this._frontFaceColorCommand.renderState = rs; this._frontFaceColorCommand.pass = Pass.TRANSLUCENT; rs = RenderState.fromCache({ depthTest: { enabled: !this.showThroughEllipsoid, }, depthMask: false, blending: BlendingState.ALPHA_BLEND, cull: { enabled: true, face: CullFace.FRONT, }, }); this._backFaceColorCommand.renderState = rs; this._backFaceColorCommand.pass = Pass.TRANSLUCENT; rs = RenderState.fromCache({ depthTest: { enabled: !this.showThroughEllipsoid, }, depthMask: false, blending: BlendingState.ALPHA_BLEND, }); this._pickCommand.renderState = rs; } else { rs = RenderState.fromCache({ depthTest: { enabled: true, }, depthMask: true, }); this._frontFaceColorCommand.renderState = rs; this._frontFaceColorCommand.pass = Pass.OPAQUE; rs = RenderState.fromCache({ depthTest: { enabled: true, }, depthMask: true, }); this._pickCommand.renderState = rs; } } // Recreate vertex buffer when directions change var directionsChanged = this._directionsDirty; if (directionsChanged) { this._directionsDirty = false; this._va = this._va && this._va.destroy(); var directions = this._directions; if (directions && directions.length >= 3) { this._frontFaceColorCommand.vertexArray = createVertexArray( this, context ); this._backFaceColorCommand.vertexArray = this._frontFaceColorCommand.vertexArray; this._pickCommand.vertexArray = this._frontFaceColorCommand.vertexArray; } } if (!defined(this._frontFaceColorCommand.vertexArray)) { return; } var pass = frameState.passes; var modelMatrixChanged = !Matrix4.equals( this.modelMatrix, this._modelMatrix ); if (modelMatrixChanged) { Matrix4.clone(this.modelMatrix, this._modelMatrix); } if (directionsChanged || modelMatrixChanged) { BoundingSphere.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 materialChanged = this._lateralSurfaceMaterial !== this.lateralSurfaceMaterial; this._lateralSurfaceMaterial = this.lateralSurfaceMaterial; this._lateralSurfaceMaterial.update(context); if (pass.render) { var frontFaceColorCommand = this._frontFaceColorCommand; var backFaceColorCommand = this._backFaceColorCommand; // Recompile shader when material changes if (materialChanged || !defined(frontFaceColorCommand.shaderProgram)) { var fsSource = new ShaderSource({ sources: [ SensorVolume, this._lateralSurfaceMaterial.shaderSource, CustomSensorVolumeFS, ], }); frontFaceColorCommand.shaderProgram = ShaderProgram.replaceCache({ context: context, shaderProgram: frontFaceColorCommand.shaderProgram, vertexShaderSource: CustomSensorVolumeVS, fragmentShaderSource: fsSource, attributeLocations: attributeLocations, }); frontFaceColorCommand.uniformMap = combine( this._uniforms, this._lateralSurfaceMaterial._uniforms ); backFaceColorCommand.shaderProgram = frontFaceColorCommand.shaderProgram; backFaceColorCommand.uniformMap = combine( this._uniforms, this._lateralSurfaceMaterial._uniforms ); // eslint-disable-next-line camelcase backFaceColorCommand.uniformMap.u_normalDirection = function () { return -1.0; }; } if (translucent) { commandList.push( this._backFaceColorCommand, this._frontFaceColorCommand ); } else { commandList.push(this._frontFaceColorCommand); } } if (pass.pick) { var pickCommand = this._pickCommand; if (!defined(this._pickId) || this._id !== this.id) { this._id = this.id; this._pickId = this._pickId && this._pickId.destroy(); this._pickId = context.createPickId({ primitive: this._pickPrimitive, id: this.id, }); } // Recompile shader when material changes if (materialChanged || !defined(pickCommand.shaderProgram)) { var pickFS = new ShaderSource({ sources: [ SensorVolume, this._lateralSurfaceMaterial.shaderSource, CustomSensorVolumeFS, ], pickColorQualifier: "uniform", }); pickCommand.shaderProgram = ShaderProgram.replaceCache({ context: context, shaderProgram: pickCommand.shaderProgram, vertexShaderSource: CustomSensorVolumeVS, fragmentShaderSource: pickFS, attributeLocations: attributeLocations, }); var that = this; var uniforms = { // eslint-disable-next-line camelcase czm_pickColor: function () { return that._pickId.color; }, }; pickCommand.uniformMap = combine( combine(this._uniforms, this._lateralSurfaceMaterial._uniforms), uniforms ); } pickCommand.pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE; commandList.push(pickCommand); } }; /** * DOC_TBA */ CustomSensorVolume.prototype.isDestroyed = function () { return false; }; /** * DOC_TBA */ CustomSensorVolume.prototype.destroy = function () { 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(); return destroyObject(this); }; return CustomSensorVolume; }); define("util/remove-primitive", ["require", "Cesium/Core/defined"], function ( require ) { "use strict"; var defined = require("Cesium/Core/defined"); return function removePrimitive(entity, hash, primitives) { var data = hash[entity.id]; if (defined(data)) { var primitive = data.primitive; primitives.remove(primitive); if (!primitive.isDestroyed()) { primitive.destroy(); } delete hash[entity.id]; } }; }); define("conic/conic-sensor-visualizer", [ "require", "Cesium/Core/AssociativeArray", "Cesium/Core/Cartesian3", "Cesium/Core/Color", "Cesium/Core/defined", "Cesium/Core/destroyObject", "Cesium/Core/DeveloperError", "Cesium/Core/Math", "Cesium/Core/Matrix3", "Cesium/Core/Matrix4", "Cesium/Core/Quaternion", "Cesium/Core/Spherical", "Cesium/DataSources/MaterialProperty", "Cesium/DataSources/Property", "../custom/custom-sensor-volume", "../util/remove-primitive", ], function (require) { "use strict"; var AssociativeArray = require("Cesium/Core/AssociativeArray"); var Cartesian3 = require("Cesium/Core/Cartesian3"); var Color = require("Cesium/Core/Color"); var defined = require("Cesium/Core/defined"); var destroyObject = require("Cesium/Core/destroyObject"); var DeveloperError = require("Cesium/Core/DeveloperError"); var CesiumMath = require("Cesium/Core/Math"); var Matrix3 = require("Cesium/Core/Matrix3"); var Matrix4 = require("Cesium/Core/Matrix4"); var Quaternion = require("Cesium/Core/Quaternion"); var Spherical = require("Cesium/Core/Spherical"); var MaterialProperty = require("Cesium/DataSources/MaterialProperty"); var Property = require("Cesium/DataSources/Property"); var CustomSensorVolume = require("../custom/custom-sensor-volume"); var removePrimitive = require("../util/remove-primitive"); var defaultIntersectionColor = Color.WHITE; var defaultIntersectionWidth = 1.0; var defaultRadius = Number.POSITIVE_INFINITY; var matrix3Scratch = new Matrix3(); var cachedPosition = new Cartesian3(); var cachedOrientation = new Quaternion(); function assignSpherical(index, array, clock, cone) { var spherical = array[index]; if (!defined(spherical)) { spherical = new Spherical(); array[index] = spherical; } spherical.clock = clock; spherical.cone = cone; spherical.magnitude = 1.0; } function computeDirections( primitive, minimumClockAngle, maximumClockAngle, innerHalfAngle, outerHalfAngle ) { var directions = primitive.directions; var angle; var i = 0; var angleStep = CesiumMath.toRadians(2.0); if ( minimumClockAngle === 0.0 && maximumClockAngle === CesiumMath.TWO_PI ) { // No clock angle limits, so this is just a circle. // There might be a hole but we're ignoring it for now. for (angle = 0.0; angle < CesiumMath.TWO_PI; angle += angleStep) { assignSpherical(i++, directions, angle, outerHalfAngle); } } else { // There are clock angle limits. for ( angle = minimumClockAngle; angle < maximumClockAngle; angle += angleStep ) { assignSpherical(i++, directions, angle, outerHalfAngle); } assignSpherical(i++, directions, maximumClockAngle, outerHalfAngle); if (innerHalfAngle) { for ( angle = maximumClockAngle; angle > minimumClockAngle; angle -= angleStep ) { assignSpherical(i++, directions, angle, innerHalfAngle); } assignSpherical(i++, directions, minimumClockAngle, innerHalfAngle); } else { assignSpherical(i++, directions, maximumClockAngle, 0.0); } } directions.length = i; primitive.directions = directions; } /** * A {@link Visualizer} which maps {@link Entity#conicSensor} to a {@link ConicSensor}. * @alias ConicSensorVisualizer * @constructor * * @param {Scene} scene The scene the primitives will be rendered in. * @param {EntityCollection} entityCollection The entityCollection to visualize. */ var ConicSensorVisualizer = function (scene, entityCollection) { // >>includeStart('debug', pragmas.debug); if (!defined(scene)) { throw new DeveloperError("scene is required."); } if (!defined(entityCollection)) { throw new DeveloperError("entityCollection is required."); } // >>includeEnd('debug'); entityCollection.collectionChanged.addEventListener( ConicSensorVisualizer.prototype._onCollectionChanged, this ); this._scene = scene; this._primitives = scene.primitives; this._entityCollection = entityCollection; this._hash = {}; this._entitiesToVisualize = new AssociativeArray(); this._onCollectionChanged( entityCollection, entityCollection.values, [], [] ); }; /** * Updates the primitives created by this visualizer to match their * Entity counterpart at the given time. * * @param {JulianDate} time The time to update to. * @returns {Boolean} This function always returns true. */ ConicSensorVisualizer.prototype.update = function (time) { // >>includeStart('debug', pragmas.debug); if (!defined(time)) { throw new DeveloperError("time is required."); } // >>includeEnd('debug'); var entities = this._entitiesToVisualize.values; var hash = this._hash; var primitives = this._primitives; for (var i = 0, len = entities.length; i < len; i++) { var entity = entities[i]; var conicSensorGraphics = entity._conicSensor; var position; var orientation; var data = hash[entity.id]; var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(conicSensorGraphics._show, time, true); if (show) { position = Property.getValueOrUndefined( entity._position, time, cachedPosition ); orientation = Property.getValueOrUndefined( entity._orientation, time, cachedOrientation ); show = defined(position) && defined(orientation); } if (!show) { // don't bother creating or updating anything else if (defined(data)) { data.primitive.show = false; } continue; } var primitive = defined(data) ? data.primitive : undefined; if (!defined(primitive)) { primitive = new CustomSensorVolume(); primitive.id = entity; primitives.add(primitive); data = { primitive: primitive, position: undefined, orientation: undefined, minimumClockAngle: undefined, maximumClockAngle: undefined, innerHalfAngle: undefined, outerHalfAngle: undefined, }; hash[entity.id] = data; } if ( !Cartesian3.equals(position, data.position) || !Quaternion.equals(orientation, data.orientation) ) { Matrix4.fromRotationTranslation( Matrix3.fromQuaternion(orientation, matrix3Scratch), position, primitive.modelMatrix ); data.position = Cartesian3.clone(position, data.position); data.orientation = Quaternion.clone(orientation, data.orientation); } primitive.show = true; var minimumClockAngle = Property.getValueOrDefault( conicSensorGraphics._minimumClockAngle, time, 0 ); var maximumClockAngle = Property.getValueOrDefault( conicSensorGraphics._maximumClockAngle, time, CesiumMath.TWO_PI ); var innerHalfAngle = Property.getValueOrDefault( conicSensorGraphics._innerHalfAngle, time, 0 ); var outerHalfAngle = Property.getValueOrDefault( conicSensorGraphics._outerHalfAngle, time, Math.PI ); if ( minimumClockAngle !== data.minimumClockAngle || maximumClockAngle !== data.maximumClockAngle || innerHalfAngle !== data.innerHalfAngle || outerHalfAngle !== data.outerHalfAngle ) { computeDirections( primitive, minimumClockAngle, maximumClockAngle, innerHalfAngle, outerHalfAngle ); data.innerHalfAngle = innerHalfAngle; data.maximumClockAngle = maximumClockAngle; data.outerHalfAngle = outerHalfAngle; data.minimumClockAngle = minimumClockAngle; } primitive.radius = Property.getValueOrDefault( conicSensorGraphics._radius, time, defaultRadius ); primitive.lateralSurfaceMaterial = MaterialProperty.getValue( time, conicSensorGraphics._lateralSurfaceMaterial, primitive.lateralSurfaceMaterial ); primitive.intersectionColor = Property.getValueOrClonedDefault( conicSensorGraphics._intersectionColor, time, defaultIntersectionColor, primitive.intersectionColor ); primitive.intersectionWidth = Property.getValueOrDefault( conicSensorGraphics._intersectionWidth, time, defaultIntersectionWidth ); } return true; }; /** * Returns true if this object was destroyed; otherwise, false. * * @returns {Boolean} True if this object was destroyed; otherwise, false. */ ConicSensorVisualizer.prototype.isDestroyed = function () { return false; }; /** * Removes and destroys all primitives created by this instance. */ ConicSensorVisualizer.prototype.destroy = function () { var entities = this._entitiesToVisualize.values; var hash = this._hash; var primitives = this._primitives; for (var i = entities.length - 1; i > -1; i--) { removePrimitive(entities[i], hash, primitives); } return destroyObject(this); }; /** * @private */ ConicSensorVisualizer.prototype._onCollectionChanged = function ( entityCollection, added, removed, changed ) { var i; var entity; var entities = this._entitiesToVisualize; var hash = this._hash; var primitives = this._primitives; for (i = added.length - 1; i > -1; i--) { entity = added[i]; if ( defined(entity._conicSensor) && defined(entity._position) && defined(entity._orientation) ) { entities.set(entity.id, entity); } } for (i = changed.length - 1; i > -1; i--) { entity = changed[i]; if ( defined(entity._conicSensor) && defined(entity._position) && defined(entity._orientation) ) { entities.set(entity.id, entity); } else { removePrimitive(entity, hash, primitives); entities.remove(entity.id); } } for (i = removed.length - 1; i > -1; i--) { entity = removed[i]; removePrimitive(entity, hash, primitives); entities.remove(entity.id); } }; return ConicSensorVisualizer; }); define("custom/custom-pattern-sensor-graphics", [ "require", "Cesium/Core/defaultValue", "Cesium/Core/defined", "Cesium/Core/DeveloperError", "Cesium/Core/Event", "Cesium/DataSources/createMaterialPropertyDescriptor", "Cesium/DataSources/createPropertyDescriptor", ], function (require) { "use strict"; var defaultValue = require("Cesium/Core/defaultValue"); var defined = require("Cesium/Core/defined"); var defineProperties = Object.defineProperties; var DeveloperError = require("Cesium/Core/DeveloperError"); var Event = require("Cesium/Core/Event"); var createMaterialPropertyDescriptor = require("Cesium/DataSources/createMaterialPropertyDescriptor"); var createPropertyDescriptor = require("Cesium/DataSources/createPropertyDescriptor"); /** * An optionally time-dynamic custom patterned sensor. * * @alias CustomPatternSensorGraphics * @constructor */ var CustomPatternSensorGraphics = function (options) { this._directions = undefined; this._directionsSubscription = undefined; this._lateralSurfaceMaterial = undefined; this._lateralSurfaceMaterialSubscription = undefined; this._intersectionColor = undefined; this._intersectionColorSubscription = undefined; this._intersectionWidth = undefined; this._intersectionWidthSubscription = undefined; this._showIntersection = undefined; this._showIntersectionSubscription = undefined; this._radius = undefined; this._radiusSubscription = undefined; this._show = undefined; this._showSubscription = undefined; this._definitionChanged = new Event(); this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT)); }; defineProperties(CustomPatternSensorGraphics.prototype, { /** * Gets the event that is raised whenever a new property is assigned. * @memberof CustomPatternSensorGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function () { return this._definitionChanged; }, }, /** * A {@link Property} which returns an array of {@link Spherical} instances representing the sensor's projection. * @memberof CustomPatternSensorGraphics.prototype * @type {Property} */ directions: createPropertyDescriptor("directions"), /** * Gets or sets the {@link MaterialProperty} specifying the the sensor's appearance. * @memberof CustomPatternSensorGraphics.prototype * @type {MaterialProperty} */ lateralSurfaceMaterial: createMaterialPropertyDescriptor( "lateralSurfaceMaterial" ), /** * 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. * @memberof CustomPatternSensorGraphics.prototype * @type {Property} */ intersectionColor: createPropertyDescriptor("intersectionColor"), /** * Gets or sets the numeric {@link Property} specifying the width of the line formed by the intersection of the sensor and other central bodies. * @memberof CustomPatternSensorGraphics.prototype * @type {Property} */ intersectionWidth: createPropertyDescriptor("intersectionWidth"), /** * Gets or sets the boolean {@link Property} specifying the visibility of the line formed by the intersection of the sensor and other central bodies. * @memberof CustomPatternSensorGraphics.prototype * @type {Property} */ showIntersection: createPropertyDescriptor("showIntersection"), /** * Gets or sets the numeric {@link Property} specifying the radius of the sensor's projection. * @memberof CustomPatternSensorGraphics.prototype * @type {Property} */ radius: createPropertyDescriptor("radius"), /** * Gets or sets the boolean {@link Property} specifying the visibility of the sensor. * @memberof CustomPatternSensorGraphics.prototype * @type {Property} */ show: createPropertyDescriptor("show"), }); /** * Duplicates a CustomPatternSensorGraphics instance. * * @param {CustomPatternSensorGraphics} [result] The object onto which to store the result. * @returns {CustomPatternSensorGraphics} The modified result parameter or a new instance if one was not provided. */ CustomPatternSensorGraphics.prototype.clone = function (result) { if (!defined(result)) { result = new CustomPatternSensorGraphics(); } result.directions = this.directions; result.radius = this.radius; result.show = this.show; result.showIntersection = this.showIntersection; result.intersectionColor = this.intersectionColor; result.intersectionWidth = this.intersectionWidth; result.lateralSurfaceMaterial = this.lateralSurfaceMaterial; return result; }; /** * Assigns each unassigned property on this object to the value * of the same property on the provided source object. * * @param {CustomPatternSensorGraphics} source The object to be merged into this object. */ CustomPatternSensorGraphics.prototype.merge = function (source) { // >>includeStart('debug', pragmas.debug); if (!defined(source)) { throw new DeveloperError("source is required."); } // >>includeEnd('debug'); this.directions = defaultValue(this.directions, source.directions); this.radius = defaultValue(this.radius, source.radius); this.show = defaultValue(this.show, source.show); this.showIntersection = defaultValue( this.showIntersection, source.showIntersection ); this.intersectionColor = defaultValue( this.intersectionColor, source.intersectionColor ); this.intersectionWidth = defaultValue( this.intersectionWidth, source.intersectionWidth ); this.lateralSurfaceMaterial = defaultValue( this.lateralSurfaceMaterial, source.lateralSurfaceMaterial ); }; return CustomPatternSensorGraphics; }); define("custom/custom-pattern-sensor-visualizer", [ "require", "Cesium/Core/AssociativeArray", "Cesium/Core/Cartesian3", "Cesium/Core/Color", "Cesium/Core/defined", "Cesium/Core/destroyObject", "Cesium/Core/DeveloperError", "Cesium/Core/Matrix3", "Cesium/Core/Matrix4", "Cesium/Core/Quaternion", "Cesium/DataSources/MaterialProperty", "Cesium/DataSources/Property", "../custom/custom-sensor-volume", "../util/remove-primitive", ], function (require) { "use strict"; var AssociativeArray = require("Cesium/Core/AssociativeArray"); var Cartesian3 = require("Cesium/Core/Cartesian3"); var Color = require("Cesium/Core/Color"); var defined = require("Cesium/Core/defined"); var destroyObject = require("Cesium/Core/destroyObject"); var DeveloperError = require("Cesium/Core/DeveloperError"); var Matrix3 = require("Cesium/Core/Matrix3"); var Matrix4 = require("Cesium/Core/Matrix4"); var Quaternion = require("Cesium/Core/Quaternion"); var MaterialProperty = require("Cesium/DataSources/MaterialProperty"); var Property = require("Cesium/DataSources/Property"); var CustomSensorVolume = require("../custom/custom-sensor-volume"); var removePrimitive = require("../util/remove-primitive"); var defaultIntersectionColor = Color.WHITE; var defaultIntersectionWidth = 1.0; var defaultRadius = Number.POSITIVE_INFINITY; var matrix3Scratch = new Matrix3(); var cachedPosition = new Cartesian3(); var cachedOrientation = new Quaternion(); /** * A {@link Visualizer} which maps {@link Entity#customPatternSensor} to a {@link CustomPatternSensor}. * @alias CustomPatternSensorVisualizer * @constructor * * @param {Scene} scene The scene the primitives will be rendered in. * @param {EntityCollection} entityCollection The entityCollection to visualize. */ var CustomPatternSensorVisualizer = function (scene, entityCollection) { // >>includeStart('debug', pragmas.debug); if (!defined(scene)) { throw new DeveloperError("scene is required."); } if (!defined(entityCollection)) { throw new DeveloperError("entityCollection is required."); } // >>includeEnd('debug'); entityCollection.collectionChanged.addEventListener( CustomPatternSensorVisualizer.prototype._onCollectionChanged, this ); this._scene = scene; this._primitives = scene.primitives; this._entityCollection = entityCollection; this._hash = {}; this._entitiesToVisualize = new AssociativeArray(); this._onCollectionChanged( entityCollection, entityCollection.values, [], [] ); }; /** * Updates the primitives created by this visualizer to match their * Entity counterpart at the given time. * * @param {JulianDate} time The time to update to. * @returns {Boolean} This function always returns true. */ CustomPatternSensorVisualizer.prototype.update = function (time) { // >>includeStart('debug', pragmas.debug); if (!defined(time)) { throw new DeveloperError("time is required."); } // >>includeEnd('debug'); var entities = this._entitiesToVisualize.values; var hash = this._hash; var primitives = this._primitives; for (var i = 0, len = entities.length; i < len; i++) { var entity = entities[i]; var customPatternSensorGraphics = entity._customPatternSensor; var position; var orientation; var directions; var data = hash[entity.id]; var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault( customPatternSensorGraphics._show, time, true ); if (show) { position = Property.getValueOrUndefined( entity._position, time, cachedPosition ); orientation = Property.getValueOrUndefined( entity._orientation, time, cachedOrientation ); directions = Property.getValueOrUndefined( customPatternSensorGraphics._directions, time ); show = defined(position) && defined(orientation) && defined(directions); } if (!show) { // don't bother creating or updating anything else if (defined(data)) { data.primitive.show = false; } continue; } var primitive = defined(data) ? data.primitive : undefined; if (!defined(primitive)) { primitive = new CustomSensorVolume(); primitive.id = entity; primitives.add(primitive); data = { primitive: primitive, position: undefined, orientation: undefined, }; hash[entity.id] = data; } if ( !Cartesian3.equals(position, data.position) || !Quaternion.equals(orientation, data.orientation) ) { Matrix4.fromRotationTranslation( Matrix3.fromQuaternion(orientation, matrix3Scratch), position, primitive.modelMatrix ); data.position = Cartesian3.clone(position, data.position); data.orientation = Quaternion.clone(orientation, data.orientation); } primitive.show = true; primitive.directions = directions; primitive.radius = Property.getValueOrDefault( customPatternSensorGraphics._radius, time, defaultRadius ); primitive.lateralSurfaceMaterial = MaterialProperty.getValue( time, customPatternSensorGraphics._lateralSurfaceMaterial, primitive.lateralSurfaceMaterial ); primitive.intersectionColor = Property.getValueOrClonedDefault( customPatternSensorGraphics._intersectionColor, time, defaultIntersectionColor, primitive.intersectionColor ); primitive.intersectionWidth = Property.getValueOrDefault( customPatternSensorGraphics._intersectionWidth, time, defaultIntersectionWidth ); } return true; }; /** * Returns true if this object was destroyed; otherwise, false. * * @returns {Boolean} True if this object was destroyed; otherwise, false. */ CustomPatternSensorVisualizer.prototype.isDestroyed = function () { return false; }; /** * Removes and destroys all primitives created by this instance. */ CustomPatternSensorVisualizer.prototype.destroy = function () { var entities = this._entitiesToVisualize.values; var hash = this._hash; var primitives = this._primitives; for (var i = entities.length - 1; i > -1; i--) { removePrimitive(entities[i], hash, primitives); } return destroyObject(this); }; /** * @private */ CustomPatternSensorVisualizer.prototype._onCollectionChanged = function ( entityCollection, added, removed, changed ) { var i; var entity; var entities = this._entitiesToVisualize; var hash = this._hash; var primitives = this._primitives; for (i = added.length - 1; i > -1; i--) { entity = added[i]; if ( defined(entity._customPatternSensor) && defined(entity._position) && defined(entity._orientation) ) { entities.set(entity.id, entity); } } for (i = changed.length - 1; i > -1; i--) { entity = changed[i]; if ( defined(entity._customPatternSensor) && defined(entity._position) && defined(entity._orientation) ) { entities.set(entity.id, entity); } else { removePrimitive(entity, hash, primitives); entities.remove(entity.id); } } for (i = removed.length - 1; i > -1; i--) { entity = removed[i]; removePrimitive(entity, hash, primitives); entities.remove(entity.id); } }; return CustomPatternSensorVisualizer; }); define("rectangular/rectangular-sensor-graphics", [ "require", "Cesium/Core/defaultValue", "Cesium/Core/defined", "Cesium/Core/DeveloperError", "Cesium/Core/Event", "Cesium/DataSources/createPropertyDescriptor", ], function (require) { "use strict"; var defaultValue = require("Cesium/Core/defaultValue"); var defined = require("Cesium/Core/defined"); var defineProperties = Object.defineProperties; var DeveloperError = require("Cesium/Core/DeveloperError"); var Event = require("Cesium/Core/Event"); var createPropertyDescriptor = require("Cesium/DataSources/createPropertyDescriptor"); /** * An optionally time-dynamic pyramid. * * @alias RectangularSensorGraphics * @constructor */ var RectangularSensorGraphics = function () { this._xHalfAngle = undefined; this._xHalfAngleSubscription = undefined; this._yHalfAngle = undefined; this._yHalfAngleSubscription = undefined; this._lateralSurfaceMaterial = undefined; this._lateralSurfaceMaterialSubscription = undefined; this._intersectionColor = undefined; this._intersectionColorSubscription = undefined; this._intersectionWidth = undefined; this._intersectionWidthSubscription = undefined; this._showIntersection = undefined; this._showIntersectionSubscription = undefined; this._radius = undefined; this._radiusSubscription = undefined; this._show = undefined; this._showSubscription = undefined; this._definitionChanged = new Event(); }; defineProperties(RectangularSensorGraphics.prototype, { /** * Gets the event that is raised whenever a new property is assigned. * @memberof RectangularSensorGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function () { return this._definitionChanged; }, }, /** * A {@link Property} which returns an array of {@link Spherical} instances representing the pyramid's projection. * @memberof RectangularSensorGraphics.prototype * @type {Property} */ xHalfAngle: createPropertyDescriptor("xHalfAngle"), /** * A {@link Property} which returns an array of {@link Spherical} instances representing the pyramid's projection. * @memberof RectangularSensorGraphics.prototype * @type {Property} */ yHalfAngle: createPropertyDescriptor("yHalfAngle"), /** * Gets or sets the {@link MaterialProperty} specifying the the pyramid's appearance. * @memberof RectangularSensorGraphics.prototype * @type {MaterialProperty} */ lateralSurfaceMaterial: createPropertyDescriptor( "lateralSurfaceMaterial" ), /** * 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. * @memberof RectangularSensorGraphics.prototype * @type {Property} */ intersectionColor: createPropertyDescriptor("intersectionColor"), /** * Gets or sets the numeric {@link Property} specifying the width of the line formed by the intersection of the pyramid and other central bodies. * @memberof RectangularSensorGraphics.prototype * @type {Property} */ intersectionWidth: createPropertyDescriptor("intersectionWidth"), /** * Gets or sets the boolean {@link Property} specifying the visibility of the line formed by the intersection of the pyramid and other central bodies. * @memberof RectangularSensorGraphics.prototype * @type {Property} */ showIntersection: createPropertyDescriptor("showIntersection"), /** * Gets or sets the numeric {@link Property} specifying the radius of the pyramid's projection. * @memberof RectangularSensorGraphics.prototype * @type {Property} */ radius: createPropertyDescriptor("radius"), /** * Gets or sets the boolean {@link Property} specifying the visibility of the pyramid. * @memberof RectangularSensorGraphics.prototype * @type {Property} */ show: createPropertyDescriptor("show"), }); /** * Duplicates a RectangularSensorGraphics instance. * * @param {RectangularSensorGraphics} [result] The object onto which to store the result. * @returns {RectangularSensorGraphics} The modified result parameter or a new instance if one was not provided. */ RectangularSensorGraphics.prototype.clone = function (result) { if (!defined(result)) { result = new RectangularSensorGraphics(); } result.xHalfAngle = this.xHalfAngle; result.yHalfAngle = this.yHalfAngle; result.radius = this.radius; result.show = this.show; result.showIntersection = this.showIntersection; result.intersectionColor = this.intersectionColor; result.intersectionWidth = this.intersectionWidth; result.lateralSurfaceMaterial = this.lateralSurfaceMaterial; return result; }; /** * Assigns each unassigned property on this object to the value * of the same property on the provided source object. * * @param {RectangularSensorGraphics} source The object to be merged into this object. */ RectangularSensorGraphics.prototype.merge = function (source) { // >>includeStart('debug', pragmas.debug); if (!defined(source)) { throw new DeveloperError("source is required."); } // >>includeEnd('debug'); this.xHalfAngle = defaultValue(this.xHalfAngle, source.xHalfAngle); this.yHalfAngle = defaultValue(this.yHalfAngle, source.yHalfAngle); this.radius = defaultValue(this.radius, source.radius); this.show = defaultValue(this.show, source.show); this.showIntersection = defaultValue( this.showIntersection, source.showIntersection ); this.intersectionColor = defaultValue( this.intersectionColor, source.intersectionColor ); this.intersectionWidth = defaultValue( this.intersectionWidth, source.intersectionWidth ); this.lateralSurfaceMaterial = defaultValue( this.lateralSurfaceMaterial, source.lateralSurfaceMaterial ); }; return RectangularSensorGraphics; }); define("rectangular/rectangular-pyramid-sensor-volume", [ "require", "Cesium/Core/clone", "Cesium/Core/defaultValue", "Cesium/Core/defined", "Cesium/Core/destroyObject", "Cesium/Core/DeveloperError", "Cesium/Core/Math", "Cesium/Core/Spherical", "../custom/custom-sensor-volume", ], function (require) { "use strict"; var clone = require("Cesium/Core/clone"); var defaultValue = require("Cesium/Core/defaultValue"); var defined = require("Cesium/Core/defined"); var defineProperties = Object.defineProperties; var destroyObject = require("Cesium/Core/destroyObject"); var DeveloperError = require("Cesium/Core/DeveloperError"); var CesiumMath = require("Cesium/Core/Math"); var Spherical = require("Cesium/Core/Spherical"); var CustomSensorVolume = require("../custom/custom-sensor-volume"); function assignSpherical(index, array, clock, cone) { var spherical = array[index]; if (!defined(spherical)) { spherical = new Spherical(); array[index] = spherical; } spherical.clock = clock; spherical.cone = cone; spherical.magnitude = 1.0; } function updateDirections(rectangularSensor) { var directions = rectangularSensor._customSensor.directions; // At 90 degrees the sensor is completely open, and tan() goes to infinity. var tanX = Math.tan( Math.min(rectangularSensor._xHalfAngle, CesiumMath.toRadians(89.0)) ); var tanY = Math.tan( Math.min(rectangularSensor._yHalfAngle, CesiumMath.toRadians(89.0)) ); var theta = Math.atan(tanX / tanY); var cone = Math.atan(Math.sqrt(tanX * tanX + tanY * tanY)); assignSpherical(0, directions, theta, cone); assignSpherical(1, directions, CesiumMath.toRadians(180.0) - theta, cone); assignSpherical(2, directions, CesiumMath.toRadians(180.0) + theta, cone); assignSpherical(3, directions, -theta, cone); directions.length = 4; rectangularSensor._customSensor.directions = directions; } var RectangularPyramidSensorVolume = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); var customSensorOptions = clone(options); customSensorOptions._pickPrimitive = defaultValue( options._pickPrimitive, this ); customSensorOptions.directions = undefined; this._customSensor = new CustomSensorVolume(customSensorOptions); this._xHalfAngle = defaultValue( options.xHalfAngle, CesiumMath.PI_OVER_TWO ); this._yHalfAngle = defaultValue( options.yHalfAngle, CesiumMath.PI_OVER_TWO ); updateDirections(this); }; defineProperties(RectangularPyramidSensorVolume.prototype, { xHalfAngle: { get: function () { return this._xHalfAngle; }, set: function (value) { // >>includeStart('debug', pragmas.debug) if (value > CesiumMath.PI_OVER_TWO) { throw new DeveloperError( "xHalfAngle must be less than or equal to 90 degrees." ); } // >>includeEnd('debug'); if (this._xHalfAngle !== value) { this._xHalfAngle = value; updateDirections(this); } }, }, yHalfAngle: { get: function () { return this._yHalfAngle; }, set: function (value) { // >>includeStart('debug', pragmas.debug) if (value > CesiumMath.PI_OVER_TWO) { throw new DeveloperError( "yHalfAngle must be less than or equal to 90 degrees." ); } // >>includeEnd('debug'); if (this._yHalfAngle !== value) { this._yHalfAngle = value; updateDirections(this); } }, }, show: { get: function () { return this._customSensor.show; }, set: function (value) { this._customSensor.show = value; }, }, showIntersection: { get: function () { return this._customSensor.showIntersection; }, set: function (value) { this._customSensor.showIntersection = value; }, }, showThroughEllipsoid: { get: function () { return this._customSensor.showThroughEllipsoid; }, set: function (value) { this._customSensor.showThroughEllipsoid = value; }, }, modelMatrix: { get: function () { return this._customSensor.modelMatrix; }, set: function (value) { this._customSensor.modelMatrix = value; }, }, radius: { get: function () { return this._customSensor.radius; }, set: function (value) { this._customSensor.radius = value; }, }, lateralSurfaceMaterial: { get: function () { return this._customSensor.lateralSurfaceMaterial; }, set: function (value) { this._customSensor.lateralSurfaceMaterial = value; }, }, intersectionColor: { get: function () { return this._customSensor.intersectionColor; }, set: function (value) { this._customSensor.intersectionColor = value; }, }, intersectionWidth: { get: function () { return this._customSensor.intersectionWidth; }, set: function (value) { this._customSensor.intersectionWidth = value; }, }, id: { get: function () { return this._customSensor.id; }, set: function (value) { this._customSensor.id = value; }, }, }); RectangularPyramidSensorVolume.prototype.update = function (frameState) { this._customSensor.update(frameState); }; RectangularPyramidSensorVolume.prototype.isDestroyed = function () { return false; }; RectangularPyramidSensorVolume.prototype.destroy = function () { this._customSensor = this._customSensor && this._customSensor.destroy(); return destroyObject(this); }; return RectangularPyramidSensorVolume; }); define("rectangular/rectangular-sensor-visualizer", [ "require", "Cesium/Core/AssociativeArray", "Cesium/Core/Cartesian3", "Cesium/Core/Color", "Cesium/Core/defined", "Cesium/Core/destroyObject", "Cesium/Core/DeveloperError", "Cesium/Core/Math", "Cesium/Core/Matrix3", "Cesium/Core/Matrix4", "Cesium/Core/Quaternion", "Cesium/DataSources/MaterialProperty", "Cesium/DataSources/Property", "./rectangular-pyramid-sensor-volume", "../util/remove-primitive", ], function (require) { "use strict"; var AssociativeArray = require("Cesium/Core/AssociativeArray"); var Cartesian3 = require("Cesium/Core/Cartesian3"); var Color = require("Cesium/Core/Color"); var defined = require("Cesium/Core/defined"); var destroyObject = require("Cesium/Core/destroyObject"); var DeveloperError = require("Cesium/Core/DeveloperError"); var CesiumMath = require("Cesium/Core/Math"); var Matrix3 = require("Cesium/Core/Matrix3"); var Matrix4 = require("Cesium/Core/Matrix4"); var Quaternion = require("Cesium/Core/Quaternion"); var MaterialProperty = require("Cesium/DataSources/MaterialProperty"); var Property = require("Cesium/DataSources/Property"); var RectangularPyramidSensorVolume = require("./rectangular-pyramid-sensor-volume"); var removePrimitive = require("../util/remove-primitive"); var defaultIntersectionColor = Color.WHITE; var defaultIntersectionWidth = 1.0; var defaultRadius = Number.POSITIVE_INFINITY; var matrix3Scratch = new Matrix3(); var cachedPosition = new Cartesian3(); var cachedOrientation = new Quaternion(); /** * A {@link Visualizer} which maps {@link Entity#rectangularSensor} to a {@link RectangularSensor}. * @alias RectangularSensorVisualizer * @constructor * * @param {Scene} scene The scene the primitives will be rendered in. * @param {EntityCollection} entityCollection The entityCollection to visualize. */ var RectangularSensorVisualizer = function (scene, entityCollection) { // >>includeStart('debug', pragmas.debug); if (!defined(scene)) { throw new DeveloperError("scene is required."); } if (!defined(entityCollection)) { throw new DeveloperError("entityCollection is required."); } // >>includeEnd('debug'); entityCollection.collectionChanged.addEventListener( RectangularSensorVisualizer.prototype._onCollectionChanged, this ); this._scene = scene; this._primitives = scene.primitives; this._entityCollection = entityCollection; this._hash = {}; this._entitiesToVisualize = new AssociativeArray(); this._onCollectionChanged( entityCollection, entityCollection.values, [], [] ); }; /** * Updates the primitives created by this visualizer to match their * Entity counterpart at the given time. * * @param {JulianDate} time The time to update to. * @returns {Boolean} This function always returns true. */ RectangularSensorVisualizer.prototype.update = function (time) { // >>includeStart('debug', pragmas.debug); if (!defined(time)) { throw new DeveloperError("time is required."); } // >>includeEnd('debug'); var entities = this._entitiesToVisualize.values; var hash = this._hash; var primitives = this._primitives; for (var i = 0, len = entities.length; i < len; i++) { var entity = entities[i]; var rectangularSensorGraphics = entity._rectangularSensorVoumes; var position; var orientation; var data = hash[entity.id]; var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault( rectangularSensorGraphics._show, time, true ); if (show) { position = Property.getValueOrUndefined( entity._position, time, cachedPosition ); orientation = Property.getValueOrUndefined( entity._orientation, time, cachedOrientation ); show = defined(position) && defined(orientation); } if (!show) { // don't bother creating or updating anything else if (defined(data)) { data.primitive.show = false; } continue; } var primitive = defined(data) ? data.primitive : undefined; if (!defined(primitive)) { primitive = new RectangularPyramidSensorVolume(); primitive.id = entity; primitives.add(primitive); data = { primitive: primitive, position: undefined, orientation: undefined, }; hash[entity.id] = data; } if ( !Cartesian3.equals(position, data.position) || !Quaternion.equals(orientation, data.orientation) ) { Matrix4.fromRotationTranslation( Matrix3.fromQuaternion(orientation, matrix3Scratch), position, primitive.modelMatrix ); data.position = Cartesian3.clone(position, data.position); data.orientation = Quaternion.clone(orientation, data.orientation); } primitive.show = true; primitive.xHalfAngle = Property.getValueOrDefault( rectangularSensorGraphics._xHalfAngle, time, CesiumMath.PI_OVER_TWO ); primitive.yHalfAngle = Property.getValueOrDefault( rectangularSensorGraphics._yHalfAngle, time, CesiumMath.PI_OVER_TWO ); primitive.radius = Property.getValueOrDefault( rectangularSensorGraphics._radius, time, defaultRadius ); primitive.lateralSurfaceMaterial = MaterialProperty.getValue( time, rectangularSensorGraphics._lateralSurfaceMaterial, primitive.lateralSurfaceMaterial ); primitive.intersectionColor = Property.getValueOrClonedDefault( rectangularSensorGraphics._intersectionColor, time, defaultIntersectionColor, primitive.intersectionColor ); primitive.intersectionWidth = Property.getValueOrDefault( rectangularSensorGraphics._intersectionWidth, time, defaultIntersectionWidth ); } return true; }; /** * Returns true if this object was destroyed; otherwise, false. * * @returns {Boolean} True if this object was destroyed; otherwise, false. */ RectangularSensorVisualizer.prototype.isDestroyed = function () { return false; }; /** * Removes and destroys all primitives created by this instance. */ RectangularSensorVisualizer.prototype.destroy = function () { var entities = this._entitiesToVisualize.values; var hash = this._hash; var primitives = this._primitives; for (var i = entities.length - 1; i > -1; i--) { removePrimitive(entities[i], hash, primitives); } return destroyObject(this); }; /** * @private */ RectangularSensorVisualizer.prototype._onCollectionChanged = function ( entityCollection, added, removed, changed ) { var i; var entity; var entities = this._entitiesToVisualize; var hash = this._hash; var primitives = this._primitives; for (i = added.length - 1; i > -1; i--) { entity = added[i]; if ( defined(entity._rectangularSensorVoumes) && defined(entity._position) && defined(entity._orientation) ) { entities.set(entity.id, entity); } } for (i = changed.length - 1; i > -1; i--) { entity = changed[i]; if ( defined(entity._rectangularSensorVoumes) && defined(entity._position) && defined(entity._orientation) ) { entities.set(entity.id, entity); } else { removePrimitive(entity, hash, primitives); entities.remove(entity.id); } } for (i = removed.length - 1; i > -1; i--) { entity = removed[i]; removePrimitive(entity, hash, primitives); entities.remove(entity.id); } }; return RectangularSensorVisualizer; }); define("initialize", [ "require", "Cesium/Core/Cartesian3", "Cesium/Core/Color", "Cesium/Core/defined", "Cesium/Core/Spherical", "Cesium/Core/TimeInterval", "Cesium/DataSources/CzmlDataSource", "Cesium/DataSources/DataSourceDisplay", "./conic/conic-sensor-graphics", "./conic/conic-sensor-visualizer", "./custom/custom-pattern-sensor-graphics", "./custom/custom-pattern-sensor-visualizer", "./rectangular/rectangular-sensor-graphics", "./rectangular/rectangular-sensor-visualizer", ], function (require) { "use strict"; var Cartesian3 = require("Cesium/Core/Cartesian3"); var Color = require("Cesium/Core/Color"); var defined = require("Cesium/Core/defined"); var Spherical = require("Cesium/Core/Spherical"); var TimeInterval = require("Cesium/Core/TimeInterval"); var CzmlDataSource = require("Cesium/DataSources/CzmlDataSource"); var DataSourceDisplay = require("Cesium/DataSources/DataSourceDisplay"); var ConicSensorGraphics = require("./conic/conic-sensor-graphics"); var ConicSensorVisualizer = require("./conic/conic-sensor-visualizer"); var CustomPatternSensorGraphics = require("./custom/custom-pattern-sensor-graphics"); var CustomPatternSensorVisualizer = require("./custom/custom-pattern-sensor-visualizer"); var RectangularSensorGraphics = require("./rectangular/rectangular-sensor-graphics"); var RectangularSensorVisualizer = require("./rectangular/rectangular-sensor-visualizer"); var processPacketData = CzmlDataSource.processPacketData; var processMaterialPacketData = CzmlDataSource.processMaterialPacketData; function processDirectionData( customPatternSensor, directions, interval, sourceUri, entityCollection ) { var i; var len; var values = []; var unitSphericals = directions.unitSpherical; var sphericals = directions.spherical; var unitCartesians = directions.unitCartesian; var cartesians = directions.cartesian; if (defined(unitSphericals)) { for (i = 0, len = unitSphericals.length; i < len; i += 2) { values.push(new Spherical(unitSphericals[i], unitSphericals[i + 1])); } directions.array = values; } else if (defined(sphericals)) { for (i = 0, len = sphericals.length; i < len; i += 3) { values.push( new Spherical(sphericals[i], sphericals[i + 1], sphericals[i + 2]) ); } directions.array = values; } else if (defined(unitCartesians)) { for (i = 0, len = unitCartesians.length; i < len; i += 3) { var tmp = Spherical.fromCartesian3( new Cartesian3( unitCartesians[i], unitCartesians[i + 1], unitCartesians[i + 2] ) ); Spherical.normalize(tmp, tmp); values.push(tmp); } directions.array = values; } else if (defined(cartesians)) { for (i = 0, len = cartesians.length; i < len; i += 3) { values.push( Spherical.fromCartesian3( new Cartesian3( cartesians[i], cartesians[i + 1], cartesians[i + 2] ) ) ); } directions.array = values; } processPacketData( Array, customPatternSensor, "directions", directions, interval, sourceUri, entityCollection ); } function processCommonSensorProperties( sensor, sensorData, interval, sourceUri, entityCollection ) { processPacketData( Boolean, sensor, "show", sensorData.show, interval, sourceUri, entityCollection ); processPacketData( Number, sensor, "radius", sensorData.radius, interval, sourceUri, entityCollection ); processPacketData( Boolean, sensor, "showIntersection", sensorData.showIntersection, interval, sourceUri, entityCollection ); processPacketData( Color, sensor, "intersectionColor", sensorData.intersectionColor, interval, sourceUri, entityCollection ); processPacketData( Number, sensor, "intersectionWidth", sensorData.intersectionWidth, interval, sourceUri, entityCollection ); processMaterialPacketData( sensor, "lateralSurfaceMaterial", sensorData.lateralSurfaceMaterial, interval, sourceUri, entityCollection ); } var iso8601Scratch = { iso8601: undefined, }; function processConicSensor(entity, packet, entityCollection, sourceUri) { var conicSensorData = packet.agi_conicSensor; if (!defined(conicSensorData)) { return; } var interval; var intervalString = conicSensorData.interval; if (defined(intervalString)) { iso8601Scratch.iso8601 = intervalString; interval = TimeInterval.fromIso8601(iso8601Scratch); } var conicSensor = entity.conicSensor; if (!defined(conicSensor)) { entity.addProperty("conicSensor"); conicSensor = new ConicSensorGraphics(); entity.conicSensor = conicSensor; } processCommonSensorProperties( conicSensor, conicSensorData, interval, sourceUri, entityCollection ); processPacketData( Number, conicSensor, "innerHalfAngle", conicSensorData.innerHalfAngle, interval, sourceUri, entityCollection ); processPacketData( Number, conicSensor, "outerHalfAngle", conicSensorData.outerHalfAngle, interval, sourceUri, entityCollection ); processPacketData( Number, conicSensor, "minimumClockAngle", conicSensorData.minimumClockAngle, interval, sourceUri, entityCollection ); processPacketData( Number, conicSensor, "maximumClockAngle", conicSensorData.maximumClockAngle, interval, sourceUri, entityCollection ); } function processCustomPatternSensor( entity, packet, entityCollection, sourceUri ) { var customPatternSensorData = packet.agi_customPatternSensor; if (!defined(customPatternSensorData)) { return; } var interval; var intervalString = customPatternSensorData.interval; if (defined(intervalString)) { iso8601Scratch.iso8601 = intervalString; interval = TimeInterval.fromIso8601(iso8601Scratch); } var customPatternSensor = entity.customPatternSensor; if (!defined(customPatternSensor)) { entity.addProperty("customPatternSensor"); customPatternSensor = new CustomPatternSensorGraphics(); entity.customPatternSensor = customPatternSensor; } processCommonSensorProperties( customPatternSensor, customPatternSensorData, interval, sourceUri, entityCollection ); // The directions property is a special case value that can be an array of unitSpherical or unit Cartesians. // We pre-process this into Spherical instances and then process it like any other array. var directions = customPatternSensorData.directions; if (defined(directions)) { if (Array.isArray(directions)) { var length = directions.length; for (var i = 0; i < length; i++) { processDirectionData( customPatternSensor, directions[i], interval, sourceUri, entityCollection ); } } else { processDirectionData( customPatternSensor, directions, interval, sourceUri, entityCollection ); } } } function processRectangularSensor( entity, packet, entityCollection, sourceUri ) { var rectangularSensorData = packet.agi_rectangularSensor; if (!defined(rectangularSensorData)) { return; } var interval; var intervalString = rectangularSensorData.interval; if (defined(intervalString)) { iso8601Scratch.iso8601 = intervalString; interval = TimeInterval.fromIso8601(iso8601Scratch); } var rectangularSensorVoumes = entity.rectangularSensorVoumes; if (!defined(rectangularSensorVoumes)) { entity.addProperty("rectangularSensorVoumes"); rectangularSensorVoumes = new RectangularSensorGraphics(); entity.rectangularSensorVoumes = rectangularSensorVoumes; } processCommonSensorProperties( rectangularSensorVoumes, rectangularSensorData, interval, sourceUri, entityCollection ); processPacketData( Number, rectangularSensorVoumes, "xHalfAngle", rectangularSensorData.xHalfAngle, interval, sourceUri, entityCollection ); processPacketData( Number, rectangularSensorVoumes, "yHalfAngle", rectangularSensorData.yHalfAngle, interval, sourceUri, entityCollection ); } var initialized = false; return function initialize() { if (initialized) { return; } CzmlDataSource.updaters.push( processConicSensor, processCustomPatternSensor, processRectangularSensor ); var originalDefaultVisualizersCallback = DataSourceDisplay.defaultVisualizersCallback; DataSourceDisplay.defaultVisualizersCallback = function ( scene, entityCluster, dataSource ) { var entities = dataSource.entities; var array = originalDefaultVisualizersCallback( scene, entityCluster, dataSource ); return array.concat([ new ConicSensorVisualizer(scene, entities), new CustomPatternSensorVisualizer(scene, entities), new RectangularSensorVisualizer(scene, entities), ]); }; initialized = true; }; }); define("cesium-sensor-volumes", [ "require", "./initialize", "./conic/conic-sensor-graphics", "./conic/conic-sensor-visualizer", "./custom/custom-pattern-sensor-graphics", "./custom/custom-pattern-sensor-visualizer", "./custom/custom-sensor-volume", "./rectangular/rectangular-pyramid-sensor-volume", "./rectangular/rectangular-sensor-graphics", "./rectangular/rectangular-sensor-visualizer", ], function (require) { "use strict"; var initialize = require("./initialize"); var ConicSensorGraphics = require("./conic/conic-sensor-graphics"); var ConicSensorVisualizer = require("./conic/conic-sensor-visualizer"); var CustomPatternSensorGraphics = require("./custom/custom-pattern-sensor-graphics"); var CustomPatternSensorVisualizer = require("./custom/custom-pattern-sensor-visualizer"); var CustomSensorVolume = require("./custom/custom-sensor-volume"); var RectangularPyramidSensorVolume = require("./rectangular/rectangular-pyramid-sensor-volume"); var RectangularSensorGraphics = require("./rectangular/rectangular-sensor-graphics"); var RectangularSensorVisualizer = require("./rectangular/rectangular-sensor-visualizer"); initialize(); return { ConicSensorGraphics: ConicSensorGraphics, ConicSensorVisualizer: ConicSensorVisualizer, CustomPatternSensorGraphics: CustomPatternSensorGraphics, CustomPatternSensorVisualizer: CustomPatternSensorVisualizer, CustomSensorVolume: CustomSensorVolume, RectangularPyramidSensorVolume: RectangularPyramidSensorVolume, RectangularSensorGraphics: RectangularSensorGraphics, RectangularSensorVisualizer: RectangularSensorVisualizer, }; }); ("use strict"); /* global Cesium */ define("Cesium/Core/Cartesian3", function () { return Cesium["Cartesian3"]; }); define("Cesium/Core/Color", function () { return Cesium["Color"]; }); define("Cesium/Core/defined", function () { return Cesium["defined"]; }); define("Cesium/Core/Spherical", function () { return Cesium["Spherical"]; }); define("Cesium/Core/TimeInterval", function () { return Cesium["TimeInterval"]; }); define("Cesium/DataSources/CzmlDataSource", function () { return Cesium["CzmlDataSource"]; }); define("Cesium/DataSources/DataSourceDisplay", function () { return Cesium["DataSourceDisplay"]; }); define("Cesium/Core/defaultValue", function () { return Cesium["defaultValue"]; }); define("Cesium/Core/DeveloperError", function () { return Cesium["DeveloperError"]; }); define("Cesium/Core/Event", function () { return Cesium["Event"]; }); define("Cesium/DataSources/createMaterialPropertyDescriptor", function () { return Cesium["createMaterialPropertyDescriptor"]; }); define("Cesium/DataSources/createPropertyDescriptor", function () { return Cesium["createPropertyDescriptor"]; }); define("Cesium/Core/AssociativeArray", function () { return Cesium["AssociativeArray"]; }); define("Cesium/Core/destroyObject", function () { return Cesium["destroyObject"]; }); define("Cesium/Core/Math", function () { return Cesium["Math"]; }); define("Cesium/Core/Matrix3", function () { return Cesium["Matrix3"]; }); define("Cesium/Core/Matrix4", function () { return Cesium["Matrix4"]; }); define("Cesium/Core/Quaternion", function () { return Cesium["Quaternion"]; }); define("Cesium/DataSources/MaterialProperty", function () { return Cesium["MaterialProperty"]; }); define("Cesium/DataSources/Property", function () { return Cesium["Property"]; }); define("Cesium/Core/BoundingSphere", function () { return Cesium["BoundingSphere"]; }); define("Cesium/Core/combine", function () { return Cesium["combine"]; }); define("Cesium/Core/ComponentDatatype", function () { return Cesium["ComponentDatatype"]; }); define("Cesium/Core/PrimitiveType", function () { return Cesium["PrimitiveType"]; }); define("Cesium/Renderer/Buffer", function () { return Cesium["Buffer"]; }); define("Cesium/Renderer/BufferUsage", function () { return Cesium["BufferUsage"]; }); define("Cesium/Renderer/DrawCommand", function () { return Cesium["DrawCommand"]; }); define("Cesium/Renderer/Pass", function () { return Cesium["Pass"]; }); define("Cesium/Renderer/RenderState", function () { return Cesium["RenderState"]; }); define("Cesium/Renderer/ShaderProgram", function () { return Cesium["ShaderProgram"]; }); define("Cesium/Renderer/ShaderSource", function () { return Cesium["ShaderSource"]; }); define("Cesium/Renderer/VertexArray", function () { return Cesium["VertexArray"]; }); define("Cesium/Scene/BlendingState", function () { return Cesium["BlendingState"]; }); define("Cesium/Scene/CullFace", function () { return Cesium["CullFace"]; }); define("Cesium/Scene/Material", function () { return Cesium["Material"]; }); define("Cesium/Scene/SceneMode", function () { return Cesium["SceneMode"]; }); define("Cesium/Core/clone", function () { return Cesium["clone"]; }); // eslint-disable-next-line import/no-dynamic-require require(["cesium-sensor-volumes"], function (CesiumSensorVolumes) { "use strict"; /* global window, self */ var scope; if (typeof window === "undefined") { if (typeof self === "undefined") { scope = {}; } else { scope = self; } } else { scope = window; } scope.CesiumSensorVolumes = CesiumSensorVolumes; }, undefined, true); })();