cesium/packages/engine/Source/Scene/PolylineCollection.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1951 lines
60 KiB
JavaScript
Raw Permalink Normal View History

Migrate Cesium to ES6 Modules See https://github.com/AnalyticalGraphicsInc/cesium/pull/8224 for details. eslint There are a handful of new .eslintrc.json files, mostly to identify the files that are still AMD modules (Sandcastle/Workers). These are needed because you can't change the parser type with a comment directive (since the parser is the thing reading the file). We can finally detect unusued modules! So those have all been cleaned up as well. requirejs -> rollup & clean-css requirejs, almond, and karma-requirejs have all been removed. We now use rollup for building and minifying (via uglify) JS code and clean-css for css. These changes are fairly straight-forward and just involve calling rollup instead of requirejs in the build process. Overall build time is significantly faster. CI is ~11 minutes compared to ~17 in master. Running makeZipFile on my machine takes 69 seconds compared to 112 seconds in master. There's probably plenty of room for additional optimization here too. We wrote an published a small npm module, rollup-plugin-strip-pragma, for stripping the requirejs pragmas we use out of the release builds. This is maintained in the Tools/rollup-plugin-strip-pragma directory. As for what we produce. The built version of Cesium is now a UMD module. So it should work anywhere that hasn't made the jump to ES6 yet. For users that were already using the "legacy" combined/minified approach, nothing changes. One awesome thing about roll-up is that it compiles all of the workers at once and automatically detects shared codes and generates separate bundles under the hood. This means the size of our worker modules shrink dramatically and Cesium itself will load them much faster. The total minified/gzipped size of all workers in master is 2.6 MB compared to 225 KB in this branch! This should be most noticeable on demos like Geometry & Appearances which load lots of workers for the various geometry typs. roll-up is also used to build Cesium Viewer, which is now an ES6 app. We use clean-css via gulp and it is also a straightforward change from requirejs that requires no special mention. Workers While the spec allows for ES6 Web Workers, no browser actually supports them yet. That means we needed a way to get our workers into non-ES6 form. Thankfully, roll-up can generate AMD modules, which means we now have a build step to compile our Worker source code back into AMD and use the existing TaskProcessor to load and execute them. This build step is part of the standard build task and is called createWorkers. During development, these "built" workers are un-optimized so you can still debug them and read the code. Since there is a build step, that means if you are changing code that affects a worker, you need to re-run build, or you can use the build-watch task to do it automatically. The ES6 versions of Worker code has moved into Source/WorkersES6 and we build the workers into their "old home" of Source/Workers. cesiumWorkerBootstrapper and transferTypedArrayTest which were already non-AMD ES5 scripts remain living in the Workers directory. Surprisingly little was changed about TaskProcessor or the worker system in general, especially considering that I thought this would be one of the major hurdles. ThirdParty A lot of our ThirdParty either already had a hand-written wrapper for AMD (which I updated to ES6) or had UMD which created problems when importing the same code in both Node and the browser. I basically had to update the wrapper of every third-party library to fix these problems. In some cases I updated the library version itself (Autolinker, topojson). Nothing to be too concerned about, but future clean-up would be using npm versions of these libraries and auto-generating the wrappers as needed so we don't hand-edit things. Sandcastle Sandcastle is eternal and manages to live another day in it's ancient requirejs/dojo 1.x form. Sandcastle now automatically uses the ES6 version of Cesium if it is available and fallsback to the ES5 unminified version if it is now. The built version of Sandcastle always uses CesiumUnminified, just like master. This means Sandcastle still works in IE11 if you run the combine step first (or use the relase zip) Removed Cesium usage from Sandcastle proper, since it wasn't really needed Generate a VERSION propertyin the gallery index since Cesium is no longer being included. Remove requirejs from Sandcastle bucket Update bucket to use the built version of Cesium if it is available by fallbackto the ES6 version during development. Standalone.html was also updated There's a bit of room for further clean-up here, but I think this gets us into master. I did not rename bucket-requirejs.html because I'm pretty sure it would break previously shared demos. We can put in some backwards compatible code later on if we want. (But I'd rather just see a full Sandcastle rewrite). Specs Specs are now all ES6, except for TestWorkers, which remain standard JS worker modules. This means you can no longer run the unbuilt unit tests in IE11. No changes for Chrome and Firefox. Since the specs use ES6 modules and built Cesium is an ES5 UMD, I added a build-specs build step which generates a combined ES5 version of the specs which rely on Cesium as a global variable. We then inject these files into jasmine instead of the standard specs and everything works exactly as it did before. SpecRunner.html has been updated to inject the correct version of the script depending on the build/release query parameters. The Specs must always use Cesium by importing Source/Cesium.js, this is so we can replace it with the built Cesium as describe above. There's a bunch of room for clean-up here, such as unifying our two copies of jasmine into a single helper file, but I didn't want to start doing that clean-up as part of this already overly big PR. The important thing is that we can still test the built version and still test on IE/Edge as needed. I also found and fixed two bugs that were causing failing unit tests, one in BingMapsImageryProviderSpec.js (which was overwriting createImage andnot setting it back) and ShadowVolumeAppearance.js (which had a module level caching bug). I think these may have been the cause of random CI failures in master as well, but only time will tell. For coverage, we had to switch to karma-coverage-istanbul-instrumenter for native ES6 support, but that's it. Finally, I updated appveryor to build Cesium and run the built tests under IE. We still don't fail the build for IE, but we should probably fix that if we want to keep it going. NodeJS When NODE_ENV is production, we now require in the minified CesiumJS directly, which works great because it's now a UMD module. Otherwise, we use the excellant esmpackage to load individual modules, it was a fairly straightforward swap from our old requirejs usage. We could probably drop esm too if we don't care about debugging or if we provie source maps at some point.
2019-10-03 23:51:23 +08:00
import BoundingSphere from "../Core/BoundingSphere.js";
import Cartesian2 from "../Core/Cartesian2.js";
import Cartesian3 from "../Core/Cartesian3.js";
import Cartesian4 from "../Core/Cartesian4.js";
import Cartographic from "../Core/Cartographic.js";
import Color from "../Core/Color.js";
import combine from "../Core/combine.js";
import ComponentDatatype from "../Core/ComponentDatatype.js";
import Frozen from "../Core/Frozen.js";
Migrate Cesium to ES6 Modules See https://github.com/AnalyticalGraphicsInc/cesium/pull/8224 for details. eslint There are a handful of new .eslintrc.json files, mostly to identify the files that are still AMD modules (Sandcastle/Workers). These are needed because you can't change the parser type with a comment directive (since the parser is the thing reading the file). We can finally detect unusued modules! So those have all been cleaned up as well. requirejs -> rollup & clean-css requirejs, almond, and karma-requirejs have all been removed. We now use rollup for building and minifying (via uglify) JS code and clean-css for css. These changes are fairly straight-forward and just involve calling rollup instead of requirejs in the build process. Overall build time is significantly faster. CI is ~11 minutes compared to ~17 in master. Running makeZipFile on my machine takes 69 seconds compared to 112 seconds in master. There's probably plenty of room for additional optimization here too. We wrote an published a small npm module, rollup-plugin-strip-pragma, for stripping the requirejs pragmas we use out of the release builds. This is maintained in the Tools/rollup-plugin-strip-pragma directory. As for what we produce. The built version of Cesium is now a UMD module. So it should work anywhere that hasn't made the jump to ES6 yet. For users that were already using the "legacy" combined/minified approach, nothing changes. One awesome thing about roll-up is that it compiles all of the workers at once and automatically detects shared codes and generates separate bundles under the hood. This means the size of our worker modules shrink dramatically and Cesium itself will load them much faster. The total minified/gzipped size of all workers in master is 2.6 MB compared to 225 KB in this branch! This should be most noticeable on demos like Geometry & Appearances which load lots of workers for the various geometry typs. roll-up is also used to build Cesium Viewer, which is now an ES6 app. We use clean-css via gulp and it is also a straightforward change from requirejs that requires no special mention. Workers While the spec allows for ES6 Web Workers, no browser actually supports them yet. That means we needed a way to get our workers into non-ES6 form. Thankfully, roll-up can generate AMD modules, which means we now have a build step to compile our Worker source code back into AMD and use the existing TaskProcessor to load and execute them. This build step is part of the standard build task and is called createWorkers. During development, these "built" workers are un-optimized so you can still debug them and read the code. Since there is a build step, that means if you are changing code that affects a worker, you need to re-run build, or you can use the build-watch task to do it automatically. The ES6 versions of Worker code has moved into Source/WorkersES6 and we build the workers into their "old home" of Source/Workers. cesiumWorkerBootstrapper and transferTypedArrayTest which were already non-AMD ES5 scripts remain living in the Workers directory. Surprisingly little was changed about TaskProcessor or the worker system in general, especially considering that I thought this would be one of the major hurdles. ThirdParty A lot of our ThirdParty either already had a hand-written wrapper for AMD (which I updated to ES6) or had UMD which created problems when importing the same code in both Node and the browser. I basically had to update the wrapper of every third-party library to fix these problems. In some cases I updated the library version itself (Autolinker, topojson). Nothing to be too concerned about, but future clean-up would be using npm versions of these libraries and auto-generating the wrappers as needed so we don't hand-edit things. Sandcastle Sandcastle is eternal and manages to live another day in it's ancient requirejs/dojo 1.x form. Sandcastle now automatically uses the ES6 version of Cesium if it is available and fallsback to the ES5 unminified version if it is now. The built version of Sandcastle always uses CesiumUnminified, just like master. This means Sandcastle still works in IE11 if you run the combine step first (or use the relase zip) Removed Cesium usage from Sandcastle proper, since it wasn't really needed Generate a VERSION propertyin the gallery index since Cesium is no longer being included. Remove requirejs from Sandcastle bucket Update bucket to use the built version of Cesium if it is available by fallbackto the ES6 version during development. Standalone.html was also updated There's a bit of room for further clean-up here, but I think this gets us into master. I did not rename bucket-requirejs.html because I'm pretty sure it would break previously shared demos. We can put in some backwards compatible code later on if we want. (But I'd rather just see a full Sandcastle rewrite). Specs Specs are now all ES6, except for TestWorkers, which remain standard JS worker modules. This means you can no longer run the unbuilt unit tests in IE11. No changes for Chrome and Firefox. Since the specs use ES6 modules and built Cesium is an ES5 UMD, I added a build-specs build step which generates a combined ES5 version of the specs which rely on Cesium as a global variable. We then inject these files into jasmine instead of the standard specs and everything works exactly as it did before. SpecRunner.html has been updated to inject the correct version of the script depending on the build/release query parameters. The Specs must always use Cesium by importing Source/Cesium.js, this is so we can replace it with the built Cesium as describe above. There's a bunch of room for clean-up here, such as unifying our two copies of jasmine into a single helper file, but I didn't want to start doing that clean-up as part of this already overly big PR. The important thing is that we can still test the built version and still test on IE/Edge as needed. I also found and fixed two bugs that were causing failing unit tests, one in BingMapsImageryProviderSpec.js (which was overwriting createImage andnot setting it back) and ShadowVolumeAppearance.js (which had a module level caching bug). I think these may have been the cause of random CI failures in master as well, but only time will tell. For coverage, we had to switch to karma-coverage-istanbul-instrumenter for native ES6 support, but that's it. Finally, I updated appveryor to build Cesium and run the built tests under IE. We still don't fail the build for IE, but we should probably fix that if we want to keep it going. NodeJS When NODE_ENV is production, we now require in the minified CesiumJS directly, which works great because it's now a UMD module. Otherwise, we use the excellant esmpackage to load individual modules, it was a fairly straightforward swap from our old requirejs usage. We could probably drop esm too if we don't care about debugging or if we provie source maps at some point.
2019-10-03 23:51:23 +08:00
import defined from "../Core/defined.js";
import destroyObject from "../Core/destroyObject.js";
import DeveloperError from "../Core/DeveloperError.js";
import EncodedCartesian3 from "../Core/EncodedCartesian3.js";
import FeatureDetection from "../Core/FeatureDetection.js";
import IndexDatatype from "../Core/IndexDatatype.js";
import Intersect from "../Core/Intersect.js";
import CesiumMath from "../Core/Math.js";
import Matrix4 from "../Core/Matrix4.js";
import Plane from "../Core/Plane.js";
import RuntimeError from "../Core/RuntimeError.js";
import Buffer from "../Renderer/Buffer.js";
import BufferUsage from "../Renderer/BufferUsage.js";
import ContextLimits from "../Renderer/ContextLimits.js";
import DrawCommand from "../Renderer/DrawCommand.js";
import Pass from "../Renderer/Pass.js";
import RenderState from "../Renderer/RenderState.js";
import ShaderProgram from "../Renderer/ShaderProgram.js";
import ShaderSource from "../Renderer/ShaderSource.js";
import Texture from "../Renderer/Texture.js";
import VertexArray from "../Renderer/VertexArray.js";
import PolylineCommon from "../Shaders/PolylineCommon.js";
import PolylineFS from "../Shaders/PolylineFS.js";
import PolylineVS from "../Shaders/PolylineVS.js";
import BatchTable from "./BatchTable.js";
import BlendingState from "./BlendingState.js";
import Material from "./Material.js";
import Polyline from "./Polyline.js";
import SceneMode from "./SceneMode.js";
2020-04-17 08:31:36 +08:00
const SHOW_INDEX = Polyline.SHOW_INDEX;
const WIDTH_INDEX = Polyline.WIDTH_INDEX;
const POSITION_INDEX = Polyline.POSITION_INDEX;
2013-02-26 06:45:15 +08:00
const MATERIAL_INDEX = Polyline.MATERIAL_INDEX;
2012-07-05 22:09:43 +08:00
//POSITION_SIZE_INDEX is needed for when the polyline's position array changes size.
//When it does, we need to recreate the indicesBuffer.
const POSITION_SIZE_INDEX = Polyline.POSITION_SIZE_INDEX;
const DISTANCE_DISPLAY_CONDITION = Polyline.DISTANCE_DISPLAY_CONDITION;
const NUMBER_OF_PROPERTIES = Polyline.NUMBER_OF_PROPERTIES;
2020-04-17 08:31:36 +08:00
const attributeLocations = {
texCoordExpandAndBatchIndex: 0,
position3DHigh: 1,
position3DLow: 2,
position2DHigh: 3,
position2DLow: 4,
prevPosition3DHigh: 5,
prevPosition3DLow: 6,
prevPosition2DHigh: 7,
prevPosition2DLow: 8,
nextPosition3DHigh: 9,
nextPosition3DLow: 10,
nextPosition2DHigh: 11,
nextPosition2DLow: 12,
};
2020-04-17 08:31:36 +08:00
/**
2012-07-03 23:18:18 +08:00
* A renderable collection of polylines.
* <br /><br />
* <div align="center">
* <img src="Images/Polyline.png" width="400" height="300" /><br />
* Example polylines
* </div>
* <br /><br />
* Polylines are added and removed from the collection using {@link PolylineCollection#add}
* and {@link PolylineCollection#remove}.
*
2012-07-04 01:58:15 +08:00
* @alias PolylineCollection
* @constructor
*
* @param {object} [options] Object with the following properties:
* @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms each polyline from model to world coordinates.
* @param {boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
* @param {boolean} [options.show=true] Determines if the polylines in the collection will be shown.
*
* @performance For best performance, prefer a few collections, each with many polylines, to
* many collections with only a few polylines each. Organize collections so that polylines
* with the same update frequency are in the same collection, i.e., polylines that do not
* change should be in one collection; polylines that change every frame should be in another
* collection; and so on.
*
* @see PolylineCollection#add
* @see PolylineCollection#remove
* @see Polyline
* @see LabelCollection
*
* @example
* // Create a polyline collection with two polylines
* const polylines = new Cesium.PolylineCollection();
* polylines.add({
2015-06-24 10:12:45 +08:00
* positions : Cesium.Cartesian3.fromDegreesArray([
* -75.10, 39.57,
* -77.02, 38.53,
* -80.50, 35.14,
* -80.12, 25.46]),
* width : 2
* });
2013-03-15 05:05:09 +08:00
*
* polylines.add({
2014-07-04 03:23:49 +08:00
* positions : Cesium.Cartesian3.fromDegreesArray([
* -73.10, 37.57,
* -75.02, 36.53,
* -78.50, 33.14,
* -78.12, 23.46]),
* width : 4
* });
*/
function PolylineCollection(options) {
options = options ?? Frozen.EMPTY_OBJECT;
2020-04-17 08:31:36 +08:00
2021-01-06 06:37:34 +08:00
/**
* Determines if polylines in this collection will be shown.
*
* @type {boolean}
2021-01-06 06:37:34 +08:00
* @default true
*/
2025-03-04 03:03:53 +08:00
this.show = options.show ?? true;
2021-01-06 06:37:34 +08:00
/**
* The 4x4 transformation matrix that transforms each polyline in this collection from model to world coordinates.
* When this is the identity matrix, the polylines are drawn in world coordinates, i.e., Earth's WGS84 coordinates.
* Local reference frames can be used by providing a different transformation matrix, like that returned
* by {@link Transforms.eastNorthUpToFixedFrame}.
*
2013-06-28 04:32:22 +08:00
* @type {Matrix4}
2013-06-28 04:51:23 +08:00
* @default {@link Matrix4.IDENTITY}
*/
2025-03-04 03:03:53 +08:00
this.modelMatrix = Matrix4.clone(options.modelMatrix ?? Matrix4.IDENTITY);
this._modelMatrix = Matrix4.clone(Matrix4.IDENTITY);
2020-04-17 08:31:36 +08:00
/**
* This property is for debugging only; it is not for production use nor is it optimized.
* <p>
2014-07-25 06:42:15 +08:00
* Draws the bounding sphere for each draw command in the primitive.
* </p>
*
* @type {boolean}
*
* @default false
*/
2025-03-04 03:03:53 +08:00
this.debugShowBoundingVolume = options.debugShowBoundingVolume ?? false;
2020-04-17 08:31:36 +08:00
this._opaqueRS = undefined;
this._translucentRS = undefined;
2020-04-17 08:31:36 +08:00
2013-03-27 04:38:14 +08:00
this._colorCommands = [];
2020-04-17 08:31:36 +08:00
this._polylinesUpdated = false;
this._polylinesRemoved = false;
this._createVertexArray = false;
this._propertiesChanged = new Uint32Array(NUMBER_OF_PROPERTIES);
2012-07-05 22:09:43 +08:00
this._polylines = [];
2012-07-04 01:58:15 +08:00
this._polylineBuckets = {};
2020-04-17 08:31:36 +08:00
// The buffer usage is determined based on the usage of the attribute over time.
this._positionBufferUsage = {
bufferUsage: BufferUsage.STATIC_DRAW,
frameCount: 0,
};
2020-04-17 08:31:36 +08:00
this._mode = undefined;
2020-04-17 08:31:36 +08:00
this._polylinesToUpdate = [];
this._vertexArrays = [];
this._positionBuffer = undefined;
this._texCoordExpandAndBatchIndexBuffer = undefined;
2020-04-17 08:31:36 +08:00
this._batchTable = undefined;
this._createBatchTable = false;
2020-04-17 08:31:36 +08:00
// Only used by Vector3DTilePoints
this._useHighlightColor = false;
this._highlightColor = Color.clone(Color.WHITE);
2020-04-17 08:31:36 +08:00
const that = this;
this._uniformMap = {
u_highlightColor: function () {
return that._highlightColor;
},
};
}
2020-04-17 08:31:36 +08:00
Object.defineProperties(PolylineCollection.prototype, {
/**
* Returns the number of polylines in this collection. This is commonly used with
* {@link PolylineCollection#get} to iterate over all the polylines
* in the collection.
* @memberof PolylineCollection.prototype
* @type {number}
*/
length: {
get: function () {
removePolylines(this);
return this._polylines.length;
},
},
});
2020-04-17 08:31:36 +08:00
/**
* Creates and adds a polyline with the specified initial properties to the collection.
* The added polyline is returned so it can be modified or removed from the collection later.
*
* @param {object}[options] A template describing the polyline's properties as shown in Example 1.
* @returns {Polyline} The polyline that was added to the collection.
*
2012-06-29 23:26:36 +08:00
* @performance After calling <code>add</code>, {@link PolylineCollection#update} is called and
* the collection's vertex buffer is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead.
* For best performance, add as many polylines as possible before calling <code>update</code>.
*
* @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
*
*
* @example
* // Example 1: Add a polyline, specifying all the default values.
* const p = polylines.add({
* show : true,
2015-08-07 03:53:19 +08:00
* positions : ellipsoid.cartographicArrayToCartesianArray([
Cesium.Cartographic.fromDegrees(-75.10, 39.57),
Cesium.Cartographic.fromDegrees(-77.02, 38.53)]),
* width : 1
* });
*
* @see PolylineCollection#remove
* @see PolylineCollection#removeAll
* @see PolylineCollection#update
*/
2019-08-27 10:00:33 +08:00
PolylineCollection.prototype.add = function (options) {
const p = new Polyline(options, this);
2012-07-05 22:09:43 +08:00
p._index = this._polylines.length;
this._polylines.push(p);
this._createVertexArray = true;
this._createBatchTable = true;
return p;
};
2020-04-17 08:31:36 +08:00
/**
* Removes a polyline from the collection.
*
* @param {Polyline} polyline The polyline to remove.
* @returns {boolean} <code>true</code> if the polyline was removed; <code>false</code> if the polyline was not found in the collection.
*
2012-06-29 23:26:36 +08:00
* @performance After calling <code>remove</code>, {@link PolylineCollection#update} is called and
* the collection's vertex buffer is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead.
* For best performance, remove as many polylines as possible before calling <code>update</code>.
* If you intend to temporarily hide a polyline, it is usually more efficient to call
* {@link Polyline#show} instead of removing and re-adding the polyline.
*
* @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
*
*
* @example
* const p = polylines.add(...);
2012-06-27 00:37:47 +08:00
* polylines.remove(p); // Returns true
*
* @see PolylineCollection#add
* @see PolylineCollection#removeAll
* @see PolylineCollection#update
* @see Polyline#show
*/
PolylineCollection.prototype.remove = function (polyline) {
if (this.contains(polyline)) {
2012-07-05 22:09:43 +08:00
this._polylinesRemoved = true;
this._createVertexArray = true;
this._createBatchTable = true;
if (defined(polyline._bucket)) {
const bucket = polyline._bucket;
bucket.shaderProgram =
bucket.shaderProgram && bucket.shaderProgram.destroy();
2020-04-17 08:31:36 +08:00
}
polyline._destroy();
return true;
2020-04-17 08:31:36 +08:00
}
return false;
2020-04-17 08:31:36 +08:00
};
/**
* Removes all polylines from the collection.
2020-04-17 08:31:36 +08:00
*
* @performance <code>O(n)</code>. It is more efficient to remove all the polylines
* from a collection and then add new ones than to create a new collection entirely.
2020-04-17 08:31:36 +08:00
*
* @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
2020-04-17 08:31:36 +08:00
*
*
* @example
* polylines.add(...);
* polylines.add(...);
* polylines.removeAll();
2020-04-17 08:31:36 +08:00
*
* @see PolylineCollection#add
* @see PolylineCollection#remove
* @see PolylineCollection#update
2020-04-17 08:31:36 +08:00
*/
PolylineCollection.prototype.removeAll = function () {
releaseShaders(this);
destroyPolylines(this);
this._polylineBuckets = {};
this._polylinesRemoved = false;
this._polylines.length = 0;
this._polylinesToUpdate.length = 0;
this._createVertexArray = true;
2020-04-17 08:31:36 +08:00
};
/**
* Determines if this collection contains the specified polyline.
2020-04-17 08:31:36 +08:00
*
* @param {Polyline} polyline The polyline to check for.
* @returns {boolean} true if this collection contains the polyline, false otherwise.
*
* @see PolylineCollection#get
*/
PolylineCollection.prototype.contains = function (polyline) {
2012-07-04 01:58:15 +08:00
return defined(polyline) && polyline._polylineCollection === this;
};
2020-04-17 08:31:36 +08:00
/**
* Returns the polyline in the collection at the specified index. Indices are zero-based
* and increase as polylines are added. Removing a polyline shifts all polylines after
2012-07-05 22:09:43 +08:00
* it to the left, changing their indices. This function is commonly used with
* {@link PolylineCollection#length} to iterate over all the polylines
* in the collection.
2020-04-17 08:31:36 +08:00
*
* @param {number} index The zero-based index of the polyline.
2012-07-05 22:09:43 +08:00
* @returns {Polyline} The polyline at the specified index.
2020-04-17 08:31:36 +08:00
*
2012-07-05 22:09:43 +08:00
* @performance If polylines were removed from the collection and
* {@link PolylineCollection#update} was not called, an implicit <code>O(n)</code>
* operation is performed.
2020-04-17 08:31:36 +08:00
*
2015-04-22 01:09:52 +08:00
* @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
2020-04-17 08:31:36 +08:00
*
* @example
2015-04-22 01:09:52 +08:00
* // Toggle the show property of every polyline in the collection
* const len = polylines.length;
* for (let i = 0; i < len; ++i) {
* const p = polylines.get(i);
* p.show = !p.show;
2020-04-17 08:31:36 +08:00
* }
*
* @see PolylineCollection#length
*/
PolylineCollection.prototype.get = function (index) {
//>>includeStart('debug', pragmas.debug);
if (!defined(index)) {
throw new DeveloperError("index is required.");
2020-04-17 08:31:36 +08:00
}
2013-12-31 04:37:32 +08:00
//>>includeEnd('debug');
2020-04-17 08:31:36 +08:00
removePolylines(this);
return this._polylines[index];
2020-04-17 08:31:36 +08:00
};
function createBatchTable(collection, context) {
if (defined(collection._batchTable)) {
collection._batchTable.destroy();
2020-04-17 08:31:36 +08:00
}
const attributes = [
2020-04-17 08:31:36 +08:00
{
functionName: "batchTable_getWidthAndShow",
componentDatatype: ComponentDatatype.UNSIGNED_BYTE,
2014-03-22 06:37:14 +08:00
componentsPerAttribute: 2,
2020-04-17 08:31:36 +08:00
},
{
2012-06-29 23:26:36 +08:00
functionName: "batchTable_getPickColor",
componentDatatype: ComponentDatatype.UNSIGNED_BYTE,
componentsPerAttribute: 4,
normalize: true,
2020-04-17 08:31:36 +08:00
},
{
functionName: "batchTable_getCenterHigh",
componentDatatype: ComponentDatatype.FLOAT,
componentsPerAttribute: 3,
2020-04-17 08:31:36 +08:00
},
{
functionName: "batchTable_getCenterLowAndRadius",
componentDatatype: ComponentDatatype.FLOAT,
componentsPerAttribute: 4,
2020-04-17 08:31:36 +08:00
},
{
functionName: "batchTable_getDistanceDisplayCondition",
componentDatatype: ComponentDatatype.FLOAT,
componentsPerAttribute: 2,
2020-04-17 08:31:36 +08:00
},
];
collection._batchTable = new BatchTable(
2020-04-17 08:31:36 +08:00
context,
2012-06-27 00:37:47 +08:00
attributes,
2014-06-03 22:18:21 +08:00
collection._polylines.length,
2020-04-17 08:31:36 +08:00
);
}
const scratchUpdatePolylineEncodedCartesian = new EncodedCartesian3();
const scratchUpdatePolylineCartesian4 = new Cartesian4();
const scratchNearFarCartesian2 = new Cartesian2();
2020-04-17 08:31:36 +08:00
/**
* Called when {@link Viewer} or {@link CesiumWidget} render the scene to
* get the draw commands needed to render this primitive.
2020-04-17 08:31:36 +08:00
* <p>
2013-12-31 04:37:32 +08:00
* Do not call this function directly. This is documented just to
* list the exceptions that may be propagated when the scene is rendered:
2020-04-17 08:31:36 +08:00
* </p>
*
2012-07-05 22:09:43 +08:00
* @exception {RuntimeError} Vertex texture fetch support is required to render primitives with per-instance attributes. The maximum number of vertex texture image units must be greater than zero.
2020-04-17 08:31:36 +08:00
*/
PolylineCollection.prototype.update = function (frameState) {
removePolylines(this);
2020-04-17 08:31:36 +08:00
2021-01-06 06:37:34 +08:00
if (this._polylines.length === 0 || !this.show) {
2020-04-17 08:31:36 +08:00
return;
}
updateMode(this, frameState);
2020-04-17 08:31:36 +08:00
const context = frameState.context;
const projection = frameState.mapProjection;
let polyline;
let properties = this._propertiesChanged;
2020-04-17 08:31:36 +08:00
if (this._createBatchTable) {
if (ContextLimits.maximumVertexTextureImageUnits === 0) {
throw new RuntimeError(
"Vertex texture fetch support is required to render polylines. The maximum number of vertex texture image units must be greater than zero.",
2020-04-17 08:31:36 +08:00
);
}
createBatchTable(this, context);
this._createBatchTable = false;
2020-04-17 08:31:36 +08:00
}
if (this._createVertexArray || computeNewBuffersUsage(this)) {
createVertexArrays(this, context, projection);
} else if (this._polylinesUpdated) {
// Polylines were modified, but no polylines were added or removed.
const polylinesToUpdate = this._polylinesToUpdate;
2012-07-09 23:44:43 +08:00
if (this._mode !== SceneMode.SCENE3D) {
const updateLength = polylinesToUpdate.length;
for (let i = 0; i < updateLength; ++i) {
polyline = polylinesToUpdate[i];
polyline.update();
2020-04-17 08:31:36 +08:00
}
}
2016-09-27 05:51:36 +08:00
// if a polyline's positions size changes, we need to recreate the vertex arrays and vertex buffers because the indices will be different.
// if a polyline's material changes, we need to recreate the VAOs and VBOs because they will be batched differently.
if (properties[POSITION_SIZE_INDEX] || properties[MATERIAL_INDEX]) {
createVertexArrays(this, context, projection);
} else {
const length = polylinesToUpdate.length;
const polylineBuckets = this._polylineBuckets;
for (let ii = 0; ii < length; ++ii) {
polyline = polylinesToUpdate[ii];
properties = polyline._propertiesChanged;
const bucket = polyline._bucket;
let index = 0;
for (const x in polylineBuckets) {
if (polylineBuckets.hasOwnProperty(x)) {
if (polylineBuckets[x] === bucket) {
if (properties[POSITION_INDEX]) {
bucket.writeUpdate(
2020-04-17 08:31:36 +08:00
index,
polyline,
this._positionBuffer,
projection,
2020-04-17 08:31:36 +08:00
);
}
break;
}
index += polylineBuckets[x].lengthOfPositions;
2020-04-17 08:31:36 +08:00
}
}
if (properties[SHOW_INDEX] || properties[WIDTH_INDEX]) {
this._batchTable.setBatchedAttribute(
polyline._index,
2020-04-17 08:31:36 +08:00
0,
new Cartesian2(polyline._width, polyline._show),
);
2020-04-17 08:31:36 +08:00
}
if (this._batchTable.attributes.length > 2) {
if (properties[POSITION_INDEX] || properties[POSITION_SIZE_INDEX]) {
const boundingSphere =
frameState.mode === SceneMode.SCENE2D
? polyline._boundingVolume2D
: polyline._boundingVolumeWC;
const encodedCenter = EncodedCartesian3.fromCartesian(
boundingSphere.center,
scratchUpdatePolylineEncodedCartesian,
2020-04-17 08:31:36 +08:00
);
const low = Cartesian4.fromElements(
encodedCenter.low.x,
encodedCenter.low.y,
encodedCenter.low.z,
boundingSphere.radius,
scratchUpdatePolylineCartesian4,
2020-04-17 08:31:36 +08:00
);
2016-09-21 02:34:10 +08:00
this._batchTable.setBatchedAttribute(
polyline._index,
2020-04-17 08:31:36 +08:00
2,
encodedCenter.high,
2020-04-17 08:31:36 +08:00
);
this._batchTable.setBatchedAttribute(polyline._index, 3, low);
2020-04-17 08:31:36 +08:00
}
if (properties[DISTANCE_DISPLAY_CONDITION]) {
const nearFarCartesian = scratchNearFarCartesian2;
nearFarCartesian.x = 0.0;
nearFarCartesian.y = Number.MAX_VALUE;
const distanceDisplayCondition = polyline.distanceDisplayCondition;
if (defined(distanceDisplayCondition)) {
nearFarCartesian.x = distanceDisplayCondition.near;
nearFarCartesian.y = distanceDisplayCondition.far;
}
this._batchTable.setBatchedAttribute(
polyline._index,
2020-04-17 08:31:36 +08:00
4,
nearFarCartesian,
2013-03-15 05:05:09 +08:00
);
2012-07-05 22:09:43 +08:00
}
}
2013-03-15 05:05:09 +08:00
2013-02-26 06:45:15 +08:00
polyline._clean();
2020-04-17 08:31:36 +08:00
}
}
2013-02-26 06:45:15 +08:00
polylinesToUpdate.length = 0;
this._polylinesUpdated = false;
2020-04-17 08:31:36 +08:00
}
2013-02-26 06:45:15 +08:00
properties = this._propertiesChanged;
for (let k = 0; k < NUMBER_OF_PROPERTIES; ++k) {
properties[k] = 0;
2020-04-17 08:31:36 +08:00
}
2013-02-26 06:45:15 +08:00
let modelMatrix = Matrix4.IDENTITY;
if (frameState.mode === SceneMode.SCENE3D) {
modelMatrix = this.modelMatrix;
2020-04-17 08:31:36 +08:00
}
2013-02-26 06:45:15 +08:00
const pass = frameState.passes;
const useDepthTest = frameState.morphTime !== 0.0;
2020-04-17 08:31:36 +08:00
2013-02-26 06:45:15 +08:00
if (
!defined(this._opaqueRS) ||
this._opaqueRS.depthTest.enabled !== useDepthTest
2020-04-17 08:31:36 +08:00
) {
2013-02-26 06:45:15 +08:00
this._opaqueRS = RenderState.fromCache({
depthMask: useDepthTest,
depthTest: {
enabled: useDepthTest,
2020-04-17 08:31:36 +08:00
},
});
}
if (
!defined(this._translucentRS) ||
2013-02-26 06:45:15 +08:00
this._translucentRS.depthTest.enabled !== useDepthTest
2020-04-17 08:31:36 +08:00
) {
2013-02-26 06:45:15 +08:00
this._translucentRS = RenderState.fromCache({
blending: BlendingState.ALPHA_BLEND,
depthMask: !useDepthTest,
depthTest: {
enabled: useDepthTest,
2020-04-17 08:31:36 +08:00
},
});
}
this._batchTable.update(frameState);
2020-04-17 08:31:36 +08:00
2013-02-26 06:45:15 +08:00
if (pass.render || pass.pick) {
const colorList = this._colorCommands;
2013-02-26 06:45:15 +08:00
createCommandLists(this, frameState, colorList, modelMatrix);
2020-04-17 08:31:36 +08:00
}
};
2013-02-26 06:45:15 +08:00
const boundingSphereScratch = new BoundingSphere();
const boundingSphereScratch2 = new BoundingSphere();
2020-04-17 08:31:36 +08:00
function createCommandLists(
polylineCollection,
frameState,
commands,
modelMatrix,
2020-04-17 08:31:36 +08:00
) {
2015-10-24 07:20:40 +08:00
const context = frameState.context;
const commandList = frameState.commandList;
2022-01-22 00:26:25 +08:00
2013-03-29 05:38:58 +08:00
const commandsLength = commands.length;
2013-10-26 09:29:09 +08:00
let commandIndex = 0;
2013-02-26 06:45:15 +08:00
let cloneBoundingSphere = true;
2022-01-22 00:26:25 +08:00
2013-02-26 06:45:15 +08:00
const vertexArrays = polylineCollection._vertexArrays;
const debugShowBoundingVolume = polylineCollection.debugShowBoundingVolume;
2022-01-22 00:26:25 +08:00
const batchTable = polylineCollection._batchTable;
const uniformCallback = batchTable.getUniformMapCallback();
2022-01-22 00:26:25 +08:00
const length = vertexArrays.length;
for (let m = 0; m < length; ++m) {
const va = vertexArrays[m];
const buckets = va.buckets;
const bucketLength = buckets.length;
2022-01-22 00:26:25 +08:00
for (let n = 0; n < bucketLength; ++n) {
const bucketLocator = buckets[n];
2022-01-22 00:26:25 +08:00
let offset = bucketLocator.offset;
const sp = bucketLocator.bucket.shaderProgram;
2022-01-22 00:26:25 +08:00
const polylines = bucketLocator.bucket.polylines;
const polylineLength = polylines.length;
let currentId;
let currentMaterial;
let count = 0;
let command;
let uniformMap;
2022-01-22 00:26:25 +08:00
for (let s = 0; s < polylineLength; ++s) {
const polyline = polylines[s];
const mId = createMaterialId(polyline._material);
if (mId !== currentId) {
2013-03-15 05:05:09 +08:00
if (defined(currentId) && count > 0) {
const translucent = currentMaterial.isTranslucent();
2020-04-17 08:31:36 +08:00
2013-03-15 05:05:09 +08:00
if (commandIndex >= commandsLength) {
command = new DrawCommand({
owner: polylineCollection,
2020-04-17 08:31:36 +08:00
});
commands.push(command);
2012-07-05 22:09:43 +08:00
} else {
command = commands[commandIndex];
}
++commandIndex;
2020-04-17 08:31:36 +08:00
uniformMap = combine(
2013-10-03 02:22:50 +08:00
uniformCallback(currentMaterial._uniforms),
polylineCollection._uniformMap,
2020-04-17 08:31:36 +08:00
);
command.boundingVolume = BoundingSphere.clone(
2013-10-03 02:22:50 +08:00
boundingSphereScratch,
command.boundingVolume,
2020-04-17 08:31:36 +08:00
);
command.modelMatrix = modelMatrix;
2013-10-03 02:22:50 +08:00
command.shaderProgram = sp;
command.vertexArray = va.va;
command.renderState = translucent
? polylineCollection._translucentRS
2013-10-03 02:22:50 +08:00
: polylineCollection._opaqueRS;
command.pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE;
command.debugShowBoundingVolume = debugShowBoundingVolume;
command.pickId = "v_pickColor";
2020-04-17 08:31:36 +08:00
command.uniformMap = uniformMap;
command.count = count;
command.offset = offset;
2020-04-17 08:31:36 +08:00
offset += count;
count = 0;
cloneBoundingSphere = true;
2020-04-17 08:31:36 +08:00
commandList.push(command);
2020-04-17 08:31:36 +08:00
}
currentMaterial = polyline._material;
currentMaterial.update(context);
currentId = mId;
}
const locators = polyline._locatorBuckets;
2012-08-15 04:08:37 +08:00
const locatorLength = locators.length;
for (let t = 0; t < locatorLength; ++t) {
const locator = locators[t];
if (locator.locator === bucketLocator) {
2012-08-22 08:14:34 +08:00
count += locator.count;
2020-04-17 08:31:36 +08:00
}
2013-05-03 08:30:44 +08:00
}
let boundingVolume;
if (frameState.mode === SceneMode.SCENE3D) {
boundingVolume = polyline._boundingVolumeWC;
} else if (frameState.mode === SceneMode.COLUMBUS_VIEW) {
2015-08-26 21:38:40 +08:00
boundingVolume = polyline._boundingVolume2D;
} else if (frameState.mode === SceneMode.SCENE2D) {
if (defined(polyline._boundingVolume2D)) {
2015-08-26 21:38:40 +08:00
boundingVolume = BoundingSphere.clone(
polyline._boundingVolume2D,
boundingSphereScratch2,
2020-04-17 08:31:36 +08:00
);
boundingVolume.center.x = 0.0;
2020-04-17 08:31:36 +08:00
}
2017-06-17 00:05:18 +08:00
} else if (
defined(polyline._boundingVolumeWC) &&
defined(polyline._boundingVolume2D)
2020-04-17 08:31:36 +08:00
) {
boundingVolume = BoundingSphere.union(
polyline._boundingVolumeWC,
polyline._boundingVolume2D,
boundingSphereScratch2,
);
}
if (cloneBoundingSphere) {
cloneBoundingSphere = false;
BoundingSphere.clone(boundingVolume, boundingSphereScratch);
} else {
BoundingSphere.union(
boundingVolume,
boundingSphereScratch,
boundingSphereScratch,
2020-04-17 08:31:36 +08:00
);
}
}
2020-04-17 08:31:36 +08:00
2013-10-24 08:22:43 +08:00
if (defined(currentId) && count > 0) {
if (commandIndex >= commandsLength) {
command = new DrawCommand({
owner: polylineCollection,
});
commands.push(command);
} else {
command = commands[commandIndex];
}
2013-03-27 04:38:14 +08:00
2013-03-29 05:38:58 +08:00
++commandIndex;
2020-04-17 08:31:36 +08:00
uniformMap = combine(
uniformCallback(currentMaterial._uniforms),
2013-03-29 05:38:58 +08:00
polylineCollection._uniformMap,
2020-04-17 08:31:36 +08:00
);
command.boundingVolume = BoundingSphere.clone(
boundingSphereScratch,
command.boundingVolume,
2020-04-17 08:31:36 +08:00
);
command.modelMatrix = modelMatrix;
command.shaderProgram = sp;
command.vertexArray = va.va;
2013-03-29 05:38:58 +08:00
command.renderState = currentMaterial.isTranslucent()
? polylineCollection._translucentRS
: polylineCollection._opaqueRS;
command.pass = currentMaterial.isTranslucent()
2013-03-29 05:38:58 +08:00
? Pass.TRANSLUCENT
: Pass.OPAQUE;
2013-03-29 05:38:58 +08:00
command.debugShowBoundingVolume = debugShowBoundingVolume;
command.pickId = "v_pickColor";
2020-04-17 08:31:36 +08:00
command.uniformMap = uniformMap;
command.count = count;
command.offset = offset;
2020-04-17 08:31:36 +08:00
cloneBoundingSphere = true;
2020-04-17 08:31:36 +08:00
commandList.push(command);
2020-04-17 08:31:36 +08:00
}
2013-03-21 03:42:43 +08:00
currentId = undefined;
}
2020-04-17 08:31:36 +08:00
}
2013-03-29 05:38:58 +08:00
commands.length = commandIndex;
2020-04-17 08:31:36 +08:00
}
/**
* Returns true if this object was destroyed; otherwise, false.
* <br /><br />
* If this object was destroyed, it should not be used; calling any function other than
* <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
*
* @returns {boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
*
* @see PolylineCollection#destroy
*/
PolylineCollection.prototype.isDestroyed = function () {
return false;
};
2020-04-17 08:31:36 +08:00
/**
* Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
* release of WebGL resources, instead of relying on the garbage collector to destroy this object.
* <br /><br />
* Once an object is destroyed, it should not be used; calling any function other than
* <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
* assign the return value (<code>undefined</code>) to the object as done in the example.
*
* @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
2014-06-04 20:35:37 +08:00
*
2020-04-17 08:31:36 +08:00
*
* @example
* polylines = polylines && polylines.destroy();
*
* @see PolylineCollection#isDestroyed
*/
PolylineCollection.prototype.destroy = function () {
destroyVertexArrays(this);
releaseShaders(this);
destroyPolylines(this);
2016-09-17 05:11:21 +08:00
this._batchTable = this._batchTable && this._batchTable.destroy();
return destroyObject(this);
};
2020-04-17 08:31:36 +08:00
function computeNewBuffersUsage(collection) {
2012-07-04 01:58:15 +08:00
let usageChanged = false;
const properties = collection._propertiesChanged;
const bufferUsage = collection._positionBufferUsage;
if (properties[POSITION_INDEX]) {
if (bufferUsage.bufferUsage !== BufferUsage.STREAM_DRAW) {
2017-06-17 00:05:18 +08:00
usageChanged = true;
bufferUsage.bufferUsage = BufferUsage.STREAM_DRAW;
bufferUsage.frameCount = 100;
} else {
2012-07-04 01:58:15 +08:00
bufferUsage.frameCount = 100;
}
} else if (bufferUsage.bufferUsage !== BufferUsage.STATIC_DRAW) {
if (bufferUsage.frameCount === 0) {
usageChanged = true;
bufferUsage.bufferUsage = BufferUsage.STATIC_DRAW;
} else {
bufferUsage.frameCount--;
}
2020-04-17 08:31:36 +08:00
}
2017-06-02 03:15:33 +08:00
return usageChanged;
2020-04-17 08:31:36 +08:00
}
2017-06-02 03:15:33 +08:00
const emptyVertexBuffer = [0.0, 0.0, 0.0];
2020-04-17 08:31:36 +08:00
2017-06-02 03:15:33 +08:00
function createVertexArrays(collection, context, projection) {
collection._createVertexArray = false;
releaseShaders(collection);
destroyVertexArrays(collection);
2017-06-02 03:15:33 +08:00
sortPolylinesIntoBuckets(collection);
2020-04-17 08:31:36 +08:00
2017-10-21 02:42:46 +08:00
//stores all of the individual indices arrays.
const totalIndices = [[]];
let indices = totalIndices[0];
2020-04-17 08:31:36 +08:00
const batchTable = collection._batchTable;
const useHighlightColor = collection._useHighlightColor;
2020-04-17 08:31:36 +08:00
2017-10-21 02:42:46 +08:00
//used to determine the vertexBuffer offset if the indicesArray goes over 64k.
//if it's the same polyline while it goes over 64k, the offset needs to backtrack componentsPerAttribute * componentDatatype bytes
//so that the polyline looks contiguous.
//if the polyline ends at the 64k mark, then the offset is just 64k * componentsPerAttribute * componentDatatype
const vertexBufferOffset = [0];
let offset = 0;
2012-07-05 22:09:43 +08:00
const vertexArrayBuckets = [[]];
let totalLength = 0;
const polylineBuckets = collection._polylineBuckets;
2020-04-17 08:31:36 +08:00
let x;
let bucket;
for (x in polylineBuckets) {
2017-10-21 02:42:46 +08:00
if (polylineBuckets.hasOwnProperty(x)) {
2017-06-02 03:15:33 +08:00
bucket = polylineBuckets[x];
bucket.updateShader(context, batchTable, useHighlightColor);
2017-06-02 03:15:33 +08:00
totalLength += bucket.lengthOfPositions;
2017-05-30 03:38:27 +08:00
}
2020-04-17 08:31:36 +08:00
}
2013-03-19 03:00:44 +08:00
if (totalLength > 0) {
const mode = collection._mode;
2020-04-17 08:31:36 +08:00
const positionArray = new Float32Array(6 * totalLength * 3);
2013-03-19 03:00:44 +08:00
const texCoordExpandAndBatchIndexArray = new Float32Array(totalLength * 4);
let position3DArray;
2020-04-17 08:31:36 +08:00
2013-03-19 03:00:44 +08:00
let positionIndex = 0;
let colorIndex = 0;
let texCoordExpandAndBatchIndexIndex = 0;
for (x in polylineBuckets) {
if (polylineBuckets.hasOwnProperty(x)) {
bucket = polylineBuckets[x];
bucket.write(
positionArray,
2013-03-19 03:00:44 +08:00
texCoordExpandAndBatchIndexArray,
positionIndex,
colorIndex,
texCoordExpandAndBatchIndexIndex,
2013-03-19 03:00:44 +08:00
batchTable,
2020-04-17 08:31:36 +08:00
context,
projection,
2020-04-17 08:31:36 +08:00
);
2013-03-19 03:00:44 +08:00
if (mode === SceneMode.MORPHING) {
if (!defined(position3DArray)) {
2013-03-19 03:00:44 +08:00
position3DArray = new Float32Array(6 * totalLength * 3);
2020-04-17 08:31:36 +08:00
}
2013-03-19 03:00:44 +08:00
bucket.writeForMorph(position3DArray, positionIndex);
2013-02-26 06:45:15 +08:00
}
2017-06-02 03:15:33 +08:00
const bucketLength = bucket.lengthOfPositions;
positionIndex += 6 * bucketLength * 3;
colorIndex += bucketLength * 4;
texCoordExpandAndBatchIndexIndex += bucketLength * 4;
offset = bucket.updateIndices(
totalIndices,
vertexBufferOffset,
vertexArrayBuckets,
2020-04-17 08:31:36 +08:00
offset,
2017-06-02 03:15:33 +08:00
);
2020-04-17 08:31:36 +08:00
}
}
2013-02-26 06:45:15 +08:00
const positionBufferUsage = collection._positionBufferUsage.bufferUsage;
const texCoordExpandAndBatchIndexBufferUsage = BufferUsage.STATIC_DRAW;
2012-07-05 22:09:43 +08:00
collection._positionBuffer = Buffer.createVertexBuffer({
context: context,
typedArray: positionArray,
usage: positionBufferUsage,
});
let position3DBuffer;
if (defined(position3DArray)) {
position3DBuffer = Buffer.createVertexBuffer({
context: context,
typedArray: position3DArray,
usage: positionBufferUsage,
});
}
collection._texCoordExpandAndBatchIndexBuffer = Buffer.createVertexBuffer({
context: context,
typedArray: texCoordExpandAndBatchIndexArray,
usage: texCoordExpandAndBatchIndexBufferUsage,
2020-04-17 08:31:36 +08:00
});
const positionSizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT;
2020-01-21 22:18:42 +08:00
const texCoordExpandAndBatchIndexSizeInBytes =
4 * Float32Array.BYTES_PER_ELEMENT;
2020-04-17 08:31:36 +08:00
2020-01-17 00:52:14 +08:00
let vbo = 0;
const numberOfIndicesArrays = totalIndices.length;
for (let k = 0; k < numberOfIndicesArrays; ++k) {
2020-01-17 04:41:36 +08:00
indices = totalIndices[k];
2020-04-17 08:31:36 +08:00
if (indices.length > 0) {
2020-01-17 00:52:14 +08:00
const indicesArray = new Uint16Array(indices);
const indexBuffer = Buffer.createIndexBuffer({
context: context,
typedArray: indicesArray,
usage: BufferUsage.STATIC_DRAW,
indexDatatype: IndexDatatype.UNSIGNED_SHORT,
2020-01-17 00:52:14 +08:00
});
2012-07-05 22:09:43 +08:00
vbo += vertexBufferOffset[k];
2020-04-17 08:31:36 +08:00
const positionHighOffset =
2020-04-17 08:31:36 +08:00
6 *
(k * (positionSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) -
vbo * positionSizeInBytes); //componentsPerAttribute(3) * componentDatatype(4)
const positionLowOffset = positionSizeInBytes + positionHighOffset;
const prevPositionHighOffset = positionSizeInBytes + positionLowOffset;
const prevPositionLowOffset =
positionSizeInBytes + prevPositionHighOffset;
const nextPositionHighOffset =
positionSizeInBytes + prevPositionLowOffset;
const nextPositionLowOffset =
positionSizeInBytes + nextPositionHighOffset;
const vertexTexCoordExpandAndBatchIndexBufferOffset =
2020-04-17 08:31:36 +08:00
k *
(texCoordExpandAndBatchIndexSizeInBytes *
CesiumMath.SIXTY_FOUR_KILOBYTES) -
vbo * texCoordExpandAndBatchIndexSizeInBytes;
2020-04-17 08:31:36 +08:00
const attributes = [
2020-04-17 08:31:36 +08:00
{
index: attributeLocations.position3DHigh,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: positionHighOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.position3DLow,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: positionLowOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.position2DHigh,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: positionHighOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.position2DLow,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: positionLowOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.prevPosition3DHigh,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: prevPositionHighOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.prevPosition3DLow,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: prevPositionLowOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.prevPosition2DHigh,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: prevPositionHighOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.prevPosition2DLow,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: prevPositionLowOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.nextPosition3DHigh,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: nextPositionHighOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.nextPosition3DLow,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: nextPositionLowOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.nextPosition2DHigh,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: nextPositionHighOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.nextPosition2DLow,
componentsPerAttribute: 3,
componentDatatype: ComponentDatatype.FLOAT,
offsetInBytes: nextPositionLowOffset,
strideInBytes: 6 * positionSizeInBytes,
2020-04-17 08:31:36 +08:00
},
{
index: attributeLocations.texCoordExpandAndBatchIndex,
componentsPerAttribute: 4,
componentDatatype: ComponentDatatype.FLOAT,
vertexBuffer: collection._texCoordExpandAndBatchIndexBuffer,
offsetInBytes: vertexTexCoordExpandAndBatchIndexBufferOffset,
2020-04-17 08:31:36 +08:00
},
];
let bufferProperty3D;
let buffer3D;
let buffer2D;
let bufferProperty2D;
2020-04-17 08:31:36 +08:00
if (mode === SceneMode.SCENE3D) {
buffer3D = collection._positionBuffer;
bufferProperty3D = "vertexBuffer";
buffer2D = emptyVertexBuffer;
bufferProperty2D = "value";
} else if (
mode === SceneMode.SCENE2D ||
mode === SceneMode.COLUMBUS_VIEW
2020-04-17 08:31:36 +08:00
) {
buffer3D = emptyVertexBuffer;
bufferProperty3D = "value";
buffer2D = collection._positionBuffer;
bufferProperty2D = "vertexBuffer";
2020-04-17 08:31:36 +08:00
} else {
buffer3D = position3DBuffer;
bufferProperty3D = "vertexBuffer";
buffer2D = collection._positionBuffer;
bufferProperty2D = "vertexBuffer";
}
attributes[0][bufferProperty3D] = buffer3D;
attributes[1][bufferProperty3D] = buffer3D;
attributes[2][bufferProperty2D] = buffer2D;
attributes[3][bufferProperty2D] = buffer2D;
attributes[4][bufferProperty3D] = buffer3D;
attributes[5][bufferProperty3D] = buffer3D;
attributes[6][bufferProperty2D] = buffer2D;
attributes[7][bufferProperty2D] = buffer2D;
attributes[8][bufferProperty3D] = buffer3D;
attributes[9][bufferProperty3D] = buffer3D;
attributes[10][bufferProperty2D] = buffer2D;
attributes[11][bufferProperty2D] = buffer2D;
2020-04-17 08:31:36 +08:00
const va = new VertexArray({
context: context,
attributes: attributes,
indexBuffer: indexBuffer,
});
collection._vertexArrays.push({
2020-04-17 08:31:36 +08:00
va: va,
buckets: vertexArrayBuckets[k],
});
}
}
2020-04-17 08:31:36 +08:00
}
}
function replacer(key, value) {
if (value instanceof Texture) {
2017-06-02 03:15:33 +08:00
return value.id;
2020-04-17 08:31:36 +08:00
}
2017-06-02 03:15:33 +08:00
return value;
2020-04-17 08:31:36 +08:00
}
const scratchUniformArray = [];
function createMaterialId(material) {
const uniforms = Material._uniformList[material.type];
const length = uniforms.length;
scratchUniformArray.length = 2.0 * length;
2020-04-17 08:31:36 +08:00
let index = 0;
2012-07-05 22:09:43 +08:00
for (let i = 0; i < length; ++i) {
const uniform = uniforms[i];
2013-03-19 03:00:44 +08:00
scratchUniformArray[index] = uniform;
scratchUniformArray[index + 1] = material._uniforms[uniform]();
2013-03-19 03:00:44 +08:00
index += 2;
2020-04-17 08:31:36 +08:00
}
return `${material.type}:${JSON.stringify(scratchUniformArray, replacer)}`;
2020-04-17 08:31:36 +08:00
}
function sortPolylinesIntoBuckets(collection) {
const mode = collection._mode;
const modelMatrix = collection._modelMatrix;
2022-01-22 00:26:25 +08:00
const polylineBuckets = (collection._polylineBuckets = {});
const polylines = collection._polylines;
const length = polylines.length;
for (let i = 0; i < length; ++i) {
const p = polylines[i];
if (p._actualPositions.length > 1) {
p.update();
const material = p.material;
let value = polylineBuckets[material.type];
if (!defined(value)) {
value = polylineBuckets[material.type] = new PolylineBucket(
material,
2020-04-17 08:31:36 +08:00
mode,
modelMatrix,
2020-04-17 08:31:36 +08:00
);
}
value.addPolyline(p);
}
2020-04-17 08:31:36 +08:00
}
}
function updateMode(collection, frameState) {
const mode = frameState.mode;
2020-04-17 08:31:36 +08:00
if (
collection._mode !== mode ||
!Matrix4.equals(collection._modelMatrix, collection.modelMatrix)
2020-04-17 08:31:36 +08:00
) {
collection._mode = mode;
collection._modelMatrix = Matrix4.clone(collection.modelMatrix);
collection._createVertexArray = true;
}
}
2020-04-17 08:31:36 +08:00
function removePolylines(collection) {
if (collection._polylinesRemoved) {
collection._polylinesRemoved = false;
const definedPolylines = [];
2020-01-16 23:26:32 +08:00
const definedPolylinesToUpdate = [];
2012-07-05 22:09:43 +08:00
let polyIndex = 0;
2020-01-16 23:26:32 +08:00
let polyline;
2020-04-17 08:31:36 +08:00
2012-07-05 22:09:43 +08:00
const length = collection._polylines.length;
for (let i = 0; i < length; ++i) {
2020-01-17 22:07:36 +08:00
polyline = collection._polylines[i];
if (!polyline.isDestroyed) {
2012-07-05 22:09:43 +08:00
polyline._index = polyIndex++;
definedPolylinesToUpdate.push(polyline);
definedPolylines.push(polyline);
}
}
collection._polylines = definedPolylines;
2013-02-26 06:45:15 +08:00
collection._polylinesToUpdate = definedPolylinesToUpdate;
2020-04-17 08:31:36 +08:00
}
}
2013-02-26 06:45:15 +08:00
function releaseShaders(collection) {
2012-07-05 22:09:43 +08:00
const polylines = collection._polylines;
const length = polylines.length;
for (let i = 0; i < length; ++i) {
if (!polylines[i].isDestroyed) {
const bucket = polylines[i]._bucket;
if (defined(bucket)) {
bucket.shaderProgram =
bucket.shaderProgram && bucket.shaderProgram.destroy();
2020-04-17 08:31:36 +08:00
}
2012-07-05 22:09:43 +08:00
}
2020-04-17 08:31:36 +08:00
}
}
function destroyVertexArrays(collection) {
const length = collection._vertexArrays.length;
for (let t = 0; t < length; ++t) {
collection._vertexArrays[t].va.destroy();
2020-04-17 08:31:36 +08:00
}
collection._vertexArrays.length = 0;
2020-04-17 08:31:36 +08:00
}
PolylineCollection.prototype._updatePolyline = function (
polyline,
propertyChanged,
2020-04-17 08:31:36 +08:00
) {
this._polylinesUpdated = true;
2018-10-16 23:31:48 +08:00
if (!polyline._dirty) {
this._polylinesToUpdate.push(polyline);
2020-04-17 08:31:36 +08:00
}
++this._propertiesChanged[propertyChanged];
2020-04-17 08:31:36 +08:00
};
function destroyPolylines(collection) {
const polylines = collection._polylines;
const length = polylines.length;
2012-07-05 22:09:43 +08:00
for (let i = 0; i < length; ++i) {
2013-02-26 06:45:15 +08:00
if (!polylines[i].isDestroyed) {
polylines[i]._destroy();
}
2020-04-17 08:31:36 +08:00
}
}
2013-03-19 05:42:34 +08:00
function VertexArrayBucketLocator(count, offset, bucket) {
2012-07-05 22:09:43 +08:00
this.count = count;
this.offset = offset;
2013-02-26 06:45:15 +08:00
this.bucket = bucket;
2020-04-17 08:31:36 +08:00
}
function PolylineBucket(material, mode, modelMatrix) {
this.polylines = [];
this.lengthOfPositions = 0;
2013-02-26 06:45:15 +08:00
this.material = material;
this.shaderProgram = undefined;
2013-03-20 04:07:38 +08:00
this.mode = mode;
this.modelMatrix = modelMatrix;
2020-04-17 08:31:36 +08:00
}
2012-07-05 22:09:43 +08:00
PolylineBucket.prototype.addPolyline = function (p) {
const polylines = this.polylines;
2012-07-05 22:09:43 +08:00
polylines.push(p);
p._actualLength = this.getPolylinePositionsLength(p);
this.lengthOfPositions += p._actualLength;
2012-07-05 22:09:43 +08:00
p._bucket = this;
};
2020-04-17 08:31:36 +08:00
PolylineBucket.prototype.updateShader = function (
context,
batchTable,
useHighlightColor,
) {
if (defined(this.shaderProgram)) {
2013-02-26 06:45:15 +08:00
return;
2020-04-17 08:31:36 +08:00
}
const defines = ["DISTANCE_DISPLAY_CONDITION"];
if (useHighlightColor) {
defines.push("VECTOR_TILE");
2020-04-17 08:31:36 +08:00
}
// Check for use of v_polylineAngle in material shader
2020-04-17 08:31:36 +08:00
if (
2022-12-16 07:11:07 +08:00
this.material.shaderSource.search(/in\s+float\s+v_polylineAngle;/g) !== -1
2020-04-17 08:31:36 +08:00
) {
2017-07-27 01:55:35 +08:00
defines.push("POLYLINE_DASH");
2020-04-17 08:31:36 +08:00
}
2018-11-02 07:08:04 +08:00
if (!FeatureDetection.isInternetExplorer()) {
defines.push("CLIP_POLYLINE");
2020-04-17 08:31:36 +08:00
}
const fs = new ShaderSource({
defines: defines,
2022-11-08 22:14:15 +08:00
sources: ["in vec4 v_pickColor;\n", this.material.shaderSource, PolylineFS],
2020-04-17 08:31:36 +08:00
});
const vsSource = batchTable.getVertexShaderCallback()(PolylineVS);
const vs = new ShaderSource({
defines: defines,
sources: [PolylineCommon, vsSource],
2020-04-17 08:31:36 +08:00
});
this.shaderProgram = ShaderProgram.fromCache({
context: context,
vertexShaderSource: vs,
fragmentShaderSource: fs,
attributeLocations: attributeLocations,
2020-04-17 08:31:36 +08:00
});
};
function intersectsIDL(polyline) {
2020-04-17 08:31:36 +08:00
return (
Cartesian3.dot(Cartesian3.UNIT_X, polyline._boundingVolume.center) < 0 ||
polyline._boundingVolume.intersectPlane(Plane.ORIGIN_ZX_PLANE) ===
Intersect.INTERSECTING
2020-04-17 08:31:36 +08:00
);
}
PolylineBucket.prototype.getPolylinePositionsLength = function (polyline) {
let length;
if (this.mode === SceneMode.SCENE3D || !intersectsIDL(polyline)) {
length = polyline._actualPositions.length;
return length * 4.0 - 4.0;
2020-04-17 08:31:36 +08:00
}
2013-03-20 04:07:38 +08:00
let count = 0;
const segmentLengths = polyline._segments.lengths;
length = segmentLengths.length;
for (let i = 0; i < length; ++i) {
count += segmentLengths[i] * 4.0 - 4.0;
2020-04-17 08:31:36 +08:00
}
return count;
2020-04-17 08:31:36 +08:00
};
const scratchWritePosition = new Cartesian3();
const scratchWritePrevPosition = new Cartesian3();
const scratchWriteNextPosition = new Cartesian3();
const scratchWriteVector = new Cartesian3();
2016-09-17 05:11:21 +08:00
const scratchPickColorCartesian = new Cartesian4();
const scratchWidthShowCartesian = new Cartesian2();
2020-04-17 08:31:36 +08:00
PolylineBucket.prototype.write = function (
positionArray,
texCoordExpandAndBatchIndexArray,
positionIndex,
colorIndex,
texCoordExpandAndBatchIndexIndex,
batchTable,
2020-04-17 08:31:36 +08:00
context,
projection,
2020-04-17 08:31:36 +08:00
) {
2013-03-20 04:07:38 +08:00
const mode = this.mode;
const maxLon = projection.ellipsoid.maximumRadius * CesiumMath.PI;
2022-01-22 00:26:25 +08:00
const polylines = this.polylines;
const length = polylines.length;
for (let i = 0; i < length; ++i) {
const polyline = polylines[i];
const width = polyline.width;
const show = polyline.show && width > 0.0;
const polylineBatchIndex = polyline._index;
const segments = this.getSegments(polyline, projection);
2013-03-20 04:07:38 +08:00
const positions = segments.positions;
const lengths = segments.lengths;
2013-03-15 05:05:09 +08:00
const positionsLength = positions.length;
2022-01-22 00:26:25 +08:00
const pickColor = polyline.getPickId(context).color;
2022-01-22 00:26:25 +08:00
2013-03-20 04:07:38 +08:00
let segmentIndex = 0;
let count = 0;
let position;
2022-01-22 00:26:25 +08:00
2013-03-15 05:05:09 +08:00
for (let j = 0; j < positionsLength; ++j) {
if (j === 0) {
2014-03-01 04:20:58 +08:00
if (polyline._loop) {
position = positions[positionsLength - 2];
2020-04-17 08:31:36 +08:00
} else {
2014-03-01 04:20:58 +08:00
position = scratchWriteVector;
Cartesian3.subtract(positions[0], positions[1], position);
Cartesian3.add(positions[0], position, position);
2013-02-26 06:45:15 +08:00
}
2020-04-17 08:31:36 +08:00
} else {
position = positions[j - 1];
}
2020-04-17 08:31:36 +08:00
Cartesian3.clone(position, scratchWritePrevPosition);
Cartesian3.clone(positions[j], scratchWritePosition);
2020-04-17 08:31:36 +08:00
if (j === positionsLength - 1) {
if (polyline._loop) {
2014-03-01 04:20:58 +08:00
position = positions[1];
} else {
position = scratchWriteVector;
Cartesian3.subtract(
2014-03-01 04:20:58 +08:00
positions[positionsLength - 1],
positions[positionsLength - 2],
2020-04-17 08:31:36 +08:00
position,
);
2017-07-27 01:55:35 +08:00
Cartesian3.add(positions[positionsLength - 1], position, position);
}
2020-04-17 08:31:36 +08:00
} else {
position = positions[j + 1];
2020-04-17 08:31:36 +08:00
}
2018-11-02 07:08:04 +08:00
Cartesian3.clone(position, scratchWriteNextPosition);
2020-04-17 08:31:36 +08:00
2018-11-02 07:08:04 +08:00
const segmentLength = lengths[segmentIndex];
2013-03-20 04:07:38 +08:00
if (j === count + segmentLength) {
count += segmentLength;
++segmentIndex;
2020-04-17 08:31:36 +08:00
}
2013-03-20 04:07:38 +08:00
const segmentStart = j - count === 0;
const segmentEnd = j === count + lengths[segmentIndex] - 1;
2020-04-17 08:31:36 +08:00
if (mode === SceneMode.SCENE2D) {
2018-11-02 07:08:04 +08:00
scratchWritePrevPosition.z = 0.0;
scratchWritePosition.z = 0.0;
scratchWriteNextPosition.z = 0.0;
2020-04-17 08:31:36 +08:00
}
2018-11-02 07:08:04 +08:00
if (mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
2020-04-17 08:31:36 +08:00
if (
(segmentStart || segmentEnd) &&
maxLon - Math.abs(scratchWritePosition.x) < 1.0
2020-04-17 08:31:36 +08:00
) {
if (
(scratchWritePosition.x < 0.0 &&
2018-11-02 07:08:04 +08:00
scratchWritePrevPosition.x > 0.0) ||
(scratchWritePosition.x > 0.0 && scratchWritePrevPosition.x < 0.0)
2020-04-17 08:31:36 +08:00
) {
Cartesian3.clone(scratchWritePosition, scratchWritePrevPosition);
2020-04-17 08:31:36 +08:00
}
if (
(scratchWritePosition.x < 0.0 &&
scratchWriteNextPosition.x > 0.0) ||
2018-11-02 07:08:04 +08:00
(scratchWritePosition.x > 0.0 && scratchWriteNextPosition.x < 0.0)
2020-04-17 08:31:36 +08:00
) {
2018-11-02 07:08:04 +08:00
Cartesian3.clone(scratchWritePosition, scratchWriteNextPosition);
2020-04-17 08:31:36 +08:00
}
2018-11-02 07:08:04 +08:00
}
2020-04-17 08:31:36 +08:00
}
const startK = segmentStart ? 2 : 0;
const endK = segmentEnd ? 2 : 4;
2020-04-17 08:31:36 +08:00
for (let k = startK; k < endK; ++k) {
EncodedCartesian3.writeElements(
scratchWritePosition,
positionArray,
positionIndex,
2020-04-17 08:31:36 +08:00
);
EncodedCartesian3.writeElements(
scratchWritePrevPosition,
positionArray,
positionIndex + 6,
2020-04-17 08:31:36 +08:00
);
EncodedCartesian3.writeElements(
scratchWriteNextPosition,
positionArray,
positionIndex + 12,
2020-04-17 08:31:36 +08:00
);
const direction = k - 2 < 0 ? -1.0 : 1.0;
texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex] =
j / (positionsLength - 1); // s tex coord
texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex + 1] =
2 * (k % 2) - 1; // expand direction
texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex + 2] =
direction;
texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex + 3] =
polylineBatchIndex;
2020-04-17 08:31:36 +08:00
positionIndex += 6 * 3;
texCoordExpandAndBatchIndexIndex += 4;
2020-04-17 08:31:36 +08:00
}
}
2016-09-17 05:11:21 +08:00
const colorCartesian = scratchPickColorCartesian;
colorCartesian.x = Color.floatToByte(pickColor.red);
colorCartesian.y = Color.floatToByte(pickColor.green);
colorCartesian.z = Color.floatToByte(pickColor.blue);
2016-09-17 05:11:21 +08:00
colorCartesian.w = Color.floatToByte(pickColor.alpha);
2020-04-17 08:31:36 +08:00
2016-09-17 05:11:21 +08:00
const widthShowCartesian = scratchWidthShowCartesian;
widthShowCartesian.x = width;
widthShowCartesian.y = show ? 1.0 : 0.0;
2020-04-17 08:31:36 +08:00
2013-03-20 04:07:38 +08:00
const boundingSphere =
mode === SceneMode.SCENE2D
2014-03-01 04:20:58 +08:00
? polyline._boundingVolume2D
: polyline._boundingVolumeWC;
const encodedCenter = EncodedCartesian3.fromCartesian(
boundingSphere.center,
scratchUpdatePolylineEncodedCartesian,
2014-03-01 04:20:58 +08:00
);
2013-03-20 04:07:38 +08:00
const high = encodedCenter.high;
const low = Cartesian4.fromElements(
encodedCenter.low.x,
encodedCenter.low.y,
encodedCenter.low.z,
boundingSphere.radius,
scratchUpdatePolylineCartesian4,
);
2020-04-17 08:31:36 +08:00
const nearFarCartesian = scratchNearFarCartesian2;
nearFarCartesian.x = 0.0;
nearFarCartesian.y = Number.MAX_VALUE;
2020-04-17 08:31:36 +08:00
const distanceDisplayCondition = polyline.distanceDisplayCondition;
if (defined(distanceDisplayCondition)) {
nearFarCartesian.x = distanceDisplayCondition.near;
nearFarCartesian.y = distanceDisplayCondition.far;
}
batchTable.setBatchedAttribute(polylineBatchIndex, 0, widthShowCartesian);
batchTable.setBatchedAttribute(polylineBatchIndex, 1, colorCartesian);
if (batchTable.attributes.length > 2) {
batchTable.setBatchedAttribute(polylineBatchIndex, 2, high);
batchTable.setBatchedAttribute(polylineBatchIndex, 3, low);
batchTable.setBatchedAttribute(polylineBatchIndex, 4, nearFarCartesian);
2012-07-05 22:09:43 +08:00
}
2020-04-17 08:31:36 +08:00
}
};
2020-04-17 08:31:36 +08:00
2013-03-15 05:05:09 +08:00
const morphPositionScratch = new Cartesian3();
const morphPrevPositionScratch = new Cartesian3();
const morphNextPositionScratch = new Cartesian3();
2014-03-01 04:20:58 +08:00
const morphVectorScratch = new Cartesian3();
2020-04-17 08:31:36 +08:00
2014-03-01 04:20:58 +08:00
PolylineBucket.prototype.writeForMorph = function (
positionArray,
positionIndex,
2020-04-17 08:31:36 +08:00
) {
const modelMatrix = this.modelMatrix;
const polylines = this.polylines;
const length = polylines.length;
2013-03-15 05:05:09 +08:00
for (let i = 0; i < length; ++i) {
const polyline = polylines[i];
const positions = polyline._segments.positions;
2014-03-01 04:20:58 +08:00
const lengths = polyline._segments.lengths;
const positionsLength = positions.length;
2022-01-22 00:26:25 +08:00
2013-03-20 04:07:38 +08:00
let segmentIndex = 0;
let count = 0;
2022-01-22 00:26:25 +08:00
for (let j = 0; j < positionsLength; ++j) {
let prevPosition;
if (j === 0) {
if (polyline._loop) {
prevPosition = positions[positionsLength - 2];
} else {
prevPosition = morphVectorScratch;
Cartesian3.subtract(positions[0], positions[1], prevPosition);
Cartesian3.add(positions[0], prevPosition, prevPosition);
2012-07-05 22:09:43 +08:00
}
} else {
2013-03-19 05:42:34 +08:00
prevPosition = positions[j - 1];
2020-04-17 08:31:36 +08:00
}
2013-03-19 05:42:34 +08:00
prevPosition = Matrix4.multiplyByPoint(
modelMatrix,
prevPosition,
morphPrevPositionScratch,
);
2020-04-17 08:31:36 +08:00
const position = Matrix4.multiplyByPoint(
2014-06-12 03:35:43 +08:00
modelMatrix,
positions[j],
morphPositionScratch,
2020-04-17 08:31:36 +08:00
);
let nextPosition;
if (j === positionsLength - 1) {
2013-02-26 06:45:15 +08:00
if (polyline._loop) {
2014-03-01 04:20:58 +08:00
nextPosition = positions[1];
2013-02-26 06:45:15 +08:00
} else {
nextPosition = morphVectorScratch;
Cartesian3.subtract(
positions[positionsLength - 1],
2012-07-09 23:44:43 +08:00
positions[positionsLength - 2],
nextPosition,
);
Cartesian3.add(
positions[positionsLength - 1],
nextPosition,
nextPosition,
2020-04-17 08:31:36 +08:00
);
}
2020-04-17 08:31:36 +08:00
} else {
2012-07-05 22:09:43 +08:00
nextPosition = positions[j + 1];
2020-04-17 08:31:36 +08:00
}
2012-07-05 22:09:43 +08:00
nextPosition = Matrix4.multiplyByPoint(
2014-06-12 03:35:43 +08:00
modelMatrix,
nextPosition,
morphNextPositionScratch,
2020-04-17 08:31:36 +08:00
);
2012-07-05 22:09:43 +08:00
const segmentLength = lengths[segmentIndex];
if (j === count + segmentLength) {
count += segmentLength;
2013-03-20 04:07:38 +08:00
++segmentIndex;
2020-04-17 08:31:36 +08:00
}
const segmentStart = j - count === 0;
const segmentEnd = j === count + lengths[segmentIndex] - 1;
2020-04-17 08:31:36 +08:00
const startK = segmentStart ? 2 : 0;
const endK = segmentEnd ? 2 : 4;
2020-04-17 08:31:36 +08:00
for (let k = startK; k < endK; ++k) {
2013-03-19 05:42:34 +08:00
EncodedCartesian3.writeElements(position, positionArray, positionIndex);
EncodedCartesian3.writeElements(
prevPosition,
positionArray,
positionIndex + 6,
2020-04-17 08:31:36 +08:00
);
EncodedCartesian3.writeElements(
nextPosition,
positionArray,
positionIndex + 12,
2020-04-17 08:31:36 +08:00
);
positionIndex += 6 * 3;
2020-04-17 08:31:36 +08:00
}
}
}
};
2013-03-19 05:42:34 +08:00
const scratchSegmentLengths = new Array(1);
2020-04-17 08:31:36 +08:00
PolylineBucket.prototype.updateIndices = function (
2013-03-19 05:42:34 +08:00
totalIndices,
vertexBufferOffset,
vertexArrayBuckets,
2020-04-17 08:31:36 +08:00
offset,
) {
let vaCount = vertexArrayBuckets.length - 1;
2013-02-26 06:45:15 +08:00
let bucketLocator = new VertexArrayBucketLocator(0, offset, this);
vertexArrayBuckets[vaCount].push(bucketLocator);
2013-03-20 04:07:38 +08:00
let count = 0;
2013-03-19 05:42:34 +08:00
let indices = totalIndices[totalIndices.length - 1];
let indicesCount = 0;
2012-07-05 22:09:43 +08:00
if (indices.length > 0) {
2013-03-19 05:42:34 +08:00
indicesCount = indices[indices.length - 1] + 1;
2020-04-17 08:31:36 +08:00
}
2013-03-19 05:42:34 +08:00
const polylines = this.polylines;
const length = polylines.length;
for (let i = 0; i < length; ++i) {
const polyline = polylines[i];
polyline._locatorBuckets = [];
2020-04-17 08:31:36 +08:00
2013-03-19 05:42:34 +08:00
let segments;
if (this.mode === SceneMode.SCENE3D) {
segments = scratchSegmentLengths;
const positionsLength = polyline._actualPositions.length;
2013-03-20 03:00:32 +08:00
if (positionsLength > 0) {
segments[0] = positionsLength;
} else {
continue;
}
2013-03-19 05:42:34 +08:00
} else {
segments = polyline._segments.lengths;
}
2013-03-15 05:05:09 +08:00
const numberOfSegments = segments.length;
if (numberOfSegments > 0) {
let segmentIndexCount = 0;
2013-03-15 05:05:09 +08:00
for (let j = 0; j < numberOfSegments; ++j) {
const segmentLength = segments[j] - 1.0;
2013-03-15 05:05:09 +08:00
for (let k = 0; k < segmentLength; ++k) {
if (indicesCount + 4 > CesiumMath.SIXTY_FOUR_KILOBYTES) {
polyline._locatorBuckets.push({
locator: bucketLocator,
count: segmentIndexCount,
});
segmentIndexCount = 0;
vertexBufferOffset.push(4);
indices = [];
totalIndices.push(indices);
indicesCount = 0;
bucketLocator.count = count;
count = 0;
offset = 0;
bucketLocator = new VertexArrayBucketLocator(0, 0, this);
vertexArrayBuckets[++vaCount] = [bucketLocator];
2020-04-17 08:31:36 +08:00
}
indices.push(indicesCount, indicesCount + 2, indicesCount + 1);
indices.push(indicesCount + 1, indicesCount + 2, indicesCount + 3);
2020-04-17 08:31:36 +08:00
segmentIndexCount += 6;
count += 6;
offset += 6;
indicesCount += 4;
}
2020-04-17 08:31:36 +08:00
}
polyline._locatorBuckets.push({
2013-02-26 06:45:15 +08:00
locator: bucketLocator,
2013-03-20 04:07:38 +08:00
count: segmentIndexCount,
2020-04-17 08:31:36 +08:00
});
if (indicesCount + 4 > CesiumMath.SIXTY_FOUR_KILOBYTES) {
vertexBufferOffset.push(0);
indices = [];
totalIndices.push(indices);
indicesCount = 0;
bucketLocator.count = count;
offset = 0;
2013-03-20 04:07:38 +08:00
count = 0;
2013-02-26 06:45:15 +08:00
bucketLocator = new VertexArrayBucketLocator(0, 0, this);
vertexArrayBuckets[++vaCount] = [bucketLocator];
2020-04-17 08:31:36 +08:00
}
}
polyline._clean();
2020-04-17 08:31:36 +08:00
}
bucketLocator.count = count;
return offset;
};
2020-04-17 08:31:36 +08:00
PolylineBucket.prototype.getPolylineStartIndex = function (polyline) {
const polylines = this.polylines;
let positionIndex = 0;
const length = polylines.length;
2012-07-09 23:44:43 +08:00
for (let i = 0; i < length; ++i) {
const p = polylines[i];
2012-07-09 23:44:43 +08:00
if (p === polyline) {
break;
}
positionIndex += p._actualLength;
}
return positionIndex;
};
2020-04-17 08:31:36 +08:00
2013-03-20 04:07:38 +08:00
const scratchSegments = {
positions: undefined,
lengths: undefined,
2020-04-17 08:31:36 +08:00
};
2013-03-20 04:07:38 +08:00
const scratchLengths = new Array(1);
const pscratch = new Cartesian3();
const scratchCartographic = new Cartographic();
2020-04-17 08:31:36 +08:00
2013-03-20 04:07:38 +08:00
PolylineBucket.prototype.getSegments = function (polyline, projection) {
2013-03-15 05:05:09 +08:00
let positions = polyline._actualPositions;
2020-04-17 08:31:36 +08:00
2013-03-20 04:07:38 +08:00
if (this.mode === SceneMode.SCENE3D) {
scratchLengths[0] = positions.length;
scratchSegments.positions = positions;
scratchSegments.lengths = scratchLengths;
2013-03-20 04:07:38 +08:00
return scratchSegments;
2020-04-17 08:31:36 +08:00
}
if (intersectsIDL(polyline)) {
2013-03-15 05:05:09 +08:00
positions = polyline._segments.positions;
2020-04-17 08:31:36 +08:00
}
const ellipsoid = projection.ellipsoid;
const newPositions = [];
const modelMatrix = this.modelMatrix;
2014-06-12 03:35:43 +08:00
const length = positions.length;
let position;
2014-06-12 03:35:43 +08:00
let p = pscratch;
2020-04-17 08:31:36 +08:00
for (let n = 0; n < length; ++n) {
position = positions[n];
p = Matrix4.multiplyByPoint(modelMatrix, position, p);
newPositions.push(
projection.project(
ellipsoid.cartesianToCartographic(p, scratchCartographic),
2020-04-17 08:31:36 +08:00
),
);
}
if (newPositions.length > 0) {
polyline._boundingVolume2D = BoundingSphere.fromPoints(
newPositions,
polyline._boundingVolume2D,
2020-04-17 08:31:36 +08:00
);
const center2D = polyline._boundingVolume2D.center;
polyline._boundingVolume2D.center = new Cartesian3(
center2D.z,
center2D.x,
center2D.y,
2020-04-17 08:31:36 +08:00
);
}
2013-03-20 04:07:38 +08:00
scratchSegments.positions = newPositions;
scratchSegments.lengths = polyline._segments.lengths;
return scratchSegments;
2020-04-17 08:31:36 +08:00
};
let scratchPositionsArray;
2020-04-17 08:31:36 +08:00
PolylineBucket.prototype.writeUpdate = function (
2020-04-17 08:31:36 +08:00
index,
polyline,
positionBuffer,
projection,
2020-04-17 08:31:36 +08:00
) {
2013-03-20 04:07:38 +08:00
const mode = this.mode;
const maxLon = projection.ellipsoid.maximumRadius * CesiumMath.PI;
2020-04-17 08:31:36 +08:00
let positionsLength = polyline._actualLength;
if (positionsLength) {
index += this.getPolylineStartIndex(polyline);
2020-04-17 08:31:36 +08:00
let positionArray = scratchPositionsArray;
const positionsArrayLength = 6 * positionsLength * 3;
2020-04-17 08:31:36 +08:00
if (
!defined(positionArray) ||
positionArray.length < positionsArrayLength
2020-04-17 08:31:36 +08:00
) {
positionArray = scratchPositionsArray = new Float32Array(
positionsArrayLength,
);
} else if (positionArray.length > positionsArrayLength) {
2013-03-20 04:07:38 +08:00
positionArray = new Float32Array(
positionArray.buffer,
2020-04-17 08:31:36 +08:00
0,
2013-03-20 04:07:38 +08:00
positionsArrayLength,
);
}
2013-03-20 04:07:38 +08:00
const segments = this.getSegments(polyline, projection);
2013-03-15 05:05:09 +08:00
const positions = segments.positions;
2013-03-20 04:07:38 +08:00
const lengths = segments.lengths;
2020-04-17 08:31:36 +08:00
let positionIndex = 0;
2013-03-20 04:07:38 +08:00
let segmentIndex = 0;
let count = 0;
let position;
2020-04-17 08:31:36 +08:00
2013-03-15 05:05:09 +08:00
positionsLength = positions.length;
2012-07-09 23:44:43 +08:00
for (let i = 0; i < positionsLength; ++i) {
if (i === 0) {
2013-03-15 05:05:09 +08:00
if (polyline._loop) {
2014-03-01 04:20:58 +08:00
position = positions[positionsLength - 2];
2020-04-17 08:31:36 +08:00
} else {
2014-03-01 04:20:58 +08:00
position = scratchWriteVector;
Cartesian3.subtract(positions[0], positions[1], position);
Cartesian3.add(positions[0], position, position);
}
} else {
position = positions[i - 1];
2020-04-17 08:31:36 +08:00
}
Cartesian3.clone(position, scratchWritePrevPosition);
Cartesian3.clone(positions[i], scratchWritePosition);
2020-04-17 08:31:36 +08:00
if (i === positionsLength - 1) {
if (polyline._loop) {
2014-03-01 04:20:58 +08:00
position = positions[1];
} else {
position = scratchWriteVector;
Cartesian3.subtract(
2014-03-01 04:20:58 +08:00
positions[positionsLength - 1],
positions[positionsLength - 2],
2020-04-17 08:31:36 +08:00
position,
);
2014-03-01 04:20:58 +08:00
Cartesian3.add(positions[positionsLength - 1], position, position);
}
2012-08-08 07:22:21 +08:00
} else {
position = positions[i + 1];
2020-04-17 08:31:36 +08:00
}
Cartesian3.clone(position, scratchWriteNextPosition);
2020-04-17 08:31:36 +08:00
const segmentLength = lengths[segmentIndex];
if (i === count + segmentLength) {
count += segmentLength;
++segmentIndex;
2020-04-17 08:31:36 +08:00
}
const segmentStart = i - count === 0;
const segmentEnd = i === count + lengths[segmentIndex] - 1;
2020-04-17 08:31:36 +08:00
if (mode === SceneMode.SCENE2D) {
scratchWritePrevPosition.z = 0.0;
scratchWritePosition.z = 0.0;
scratchWriteNextPosition.z = 0.0;
2020-04-17 08:31:36 +08:00
}
if (mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
2020-04-17 08:31:36 +08:00
if (
(segmentStart || segmentEnd) &&
maxLon - Math.abs(scratchWritePosition.x) < 1.0
2020-04-17 08:31:36 +08:00
) {
if (
(scratchWritePosition.x < 0.0 &&
scratchWritePrevPosition.x > 0.0) ||
(scratchWritePosition.x > 0.0 && scratchWritePrevPosition.x < 0.0)
2020-04-17 08:31:36 +08:00
) {
Cartesian3.clone(scratchWritePosition, scratchWritePrevPosition);
2020-04-17 08:31:36 +08:00
}
if (
(scratchWritePosition.x < 0.0 &&
scratchWriteNextPosition.x > 0.0) ||
(scratchWritePosition.x > 0.0 && scratchWriteNextPosition.x < 0.0)
2020-04-17 08:31:36 +08:00
) {
Cartesian3.clone(scratchWritePosition, scratchWriteNextPosition);
2020-04-17 08:31:36 +08:00
}
}
2020-04-17 08:31:36 +08:00
}
const startJ = segmentStart ? 2 : 0;
const endJ = segmentEnd ? 2 : 4;
2020-04-17 08:31:36 +08:00
for (let j = startJ; j < endJ; ++j) {
EncodedCartesian3.writeElements(
scratchWritePosition,
positionArray,
positionIndex,
2020-04-17 08:31:36 +08:00
);
EncodedCartesian3.writeElements(
scratchWritePrevPosition,
positionArray,
positionIndex + 6,
2020-04-17 08:31:36 +08:00
);
EncodedCartesian3.writeElements(
scratchWriteNextPosition,
positionArray,
positionIndex + 12,
2020-04-17 08:31:36 +08:00
);
positionIndex += 6 * 3;
2020-04-17 08:31:36 +08:00
}
}
positionBuffer.copyFromArrayView(
positionArray,
6 * 3 * Float32Array.BYTES_PER_ELEMENT * index,
);
2016-03-19 04:58:18 +08:00
}
};
Migrate Cesium to ES6 Modules See https://github.com/AnalyticalGraphicsInc/cesium/pull/8224 for details. eslint There are a handful of new .eslintrc.json files, mostly to identify the files that are still AMD modules (Sandcastle/Workers). These are needed because you can't change the parser type with a comment directive (since the parser is the thing reading the file). We can finally detect unusued modules! So those have all been cleaned up as well. requirejs -> rollup & clean-css requirejs, almond, and karma-requirejs have all been removed. We now use rollup for building and minifying (via uglify) JS code and clean-css for css. These changes are fairly straight-forward and just involve calling rollup instead of requirejs in the build process. Overall build time is significantly faster. CI is ~11 minutes compared to ~17 in master. Running makeZipFile on my machine takes 69 seconds compared to 112 seconds in master. There's probably plenty of room for additional optimization here too. We wrote an published a small npm module, rollup-plugin-strip-pragma, for stripping the requirejs pragmas we use out of the release builds. This is maintained in the Tools/rollup-plugin-strip-pragma directory. As for what we produce. The built version of Cesium is now a UMD module. So it should work anywhere that hasn't made the jump to ES6 yet. For users that were already using the "legacy" combined/minified approach, nothing changes. One awesome thing about roll-up is that it compiles all of the workers at once and automatically detects shared codes and generates separate bundles under the hood. This means the size of our worker modules shrink dramatically and Cesium itself will load them much faster. The total minified/gzipped size of all workers in master is 2.6 MB compared to 225 KB in this branch! This should be most noticeable on demos like Geometry & Appearances which load lots of workers for the various geometry typs. roll-up is also used to build Cesium Viewer, which is now an ES6 app. We use clean-css via gulp and it is also a straightforward change from requirejs that requires no special mention. Workers While the spec allows for ES6 Web Workers, no browser actually supports them yet. That means we needed a way to get our workers into non-ES6 form. Thankfully, roll-up can generate AMD modules, which means we now have a build step to compile our Worker source code back into AMD and use the existing TaskProcessor to load and execute them. This build step is part of the standard build task and is called createWorkers. During development, these "built" workers are un-optimized so you can still debug them and read the code. Since there is a build step, that means if you are changing code that affects a worker, you need to re-run build, or you can use the build-watch task to do it automatically. The ES6 versions of Worker code has moved into Source/WorkersES6 and we build the workers into their "old home" of Source/Workers. cesiumWorkerBootstrapper and transferTypedArrayTest which were already non-AMD ES5 scripts remain living in the Workers directory. Surprisingly little was changed about TaskProcessor or the worker system in general, especially considering that I thought this would be one of the major hurdles. ThirdParty A lot of our ThirdParty either already had a hand-written wrapper for AMD (which I updated to ES6) or had UMD which created problems when importing the same code in both Node and the browser. I basically had to update the wrapper of every third-party library to fix these problems. In some cases I updated the library version itself (Autolinker, topojson). Nothing to be too concerned about, but future clean-up would be using npm versions of these libraries and auto-generating the wrappers as needed so we don't hand-edit things. Sandcastle Sandcastle is eternal and manages to live another day in it's ancient requirejs/dojo 1.x form. Sandcastle now automatically uses the ES6 version of Cesium if it is available and fallsback to the ES5 unminified version if it is now. The built version of Sandcastle always uses CesiumUnminified, just like master. This means Sandcastle still works in IE11 if you run the combine step first (or use the relase zip) Removed Cesium usage from Sandcastle proper, since it wasn't really needed Generate a VERSION propertyin the gallery index since Cesium is no longer being included. Remove requirejs from Sandcastle bucket Update bucket to use the built version of Cesium if it is available by fallbackto the ES6 version during development. Standalone.html was also updated There's a bit of room for further clean-up here, but I think this gets us into master. I did not rename bucket-requirejs.html because I'm pretty sure it would break previously shared demos. We can put in some backwards compatible code later on if we want. (But I'd rather just see a full Sandcastle rewrite). Specs Specs are now all ES6, except for TestWorkers, which remain standard JS worker modules. This means you can no longer run the unbuilt unit tests in IE11. No changes for Chrome and Firefox. Since the specs use ES6 modules and built Cesium is an ES5 UMD, I added a build-specs build step which generates a combined ES5 version of the specs which rely on Cesium as a global variable. We then inject these files into jasmine instead of the standard specs and everything works exactly as it did before. SpecRunner.html has been updated to inject the correct version of the script depending on the build/release query parameters. The Specs must always use Cesium by importing Source/Cesium.js, this is so we can replace it with the built Cesium as describe above. There's a bunch of room for clean-up here, such as unifying our two copies of jasmine into a single helper file, but I didn't want to start doing that clean-up as part of this already overly big PR. The important thing is that we can still test the built version and still test on IE/Edge as needed. I also found and fixed two bugs that were causing failing unit tests, one in BingMapsImageryProviderSpec.js (which was overwriting createImage andnot setting it back) and ShadowVolumeAppearance.js (which had a module level caching bug). I think these may have been the cause of random CI failures in master as well, but only time will tell. For coverage, we had to switch to karma-coverage-istanbul-instrumenter for native ES6 support, but that's it. Finally, I updated appveryor to build Cesium and run the built tests under IE. We still don't fail the build for IE, but we should probably fix that if we want to keep it going. NodeJS When NODE_ENV is production, we now require in the minified CesiumJS directly, which works great because it's now a UMD module. Otherwise, we use the excellant esmpackage to load individual modules, it was a fairly straightforward swap from our old requirejs usage. We could probably drop esm too if we don't care about debugging or if we provie source maps at some point.
2019-10-03 23:51:23 +08:00
export default PolylineCollection;