123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- import arrayRemoveDuplicates from "../Core/arrayRemoveDuplicates.js";
- import BoundingSphere from "../Core/BoundingSphere.js";
- import Cartesian3 from "../Core/Cartesian3.js";
- import Color from "../Core/Color.js";
- import defaultValue from "../Core/defaultValue.js";
- import defined from "../Core/defined.js";
- import DeveloperError from "../Core/DeveloperError.js";
- import DistanceDisplayCondition from "../Core/DistanceDisplayCondition.js";
- import Matrix4 from "../Core/Matrix4.js";
- import PolylinePipeline from "../Core/PolylinePipeline.js";
- import Material from "./Material.js";
- /**
- * A renderable polyline. Create this by calling {@link PolylineCollection#add}
- *
- * @alias Polyline
- * @internalConstructor
- * @class
- *
- * @param {Object} options Object with the following properties:
- * @param {Boolean} [options.show=true] <code>true</code> if this polyline will be shown; otherwise, <code>false</code>.
- * @param {Number} [options.width=1.0] The width of the polyline in pixels.
- * @param {Boolean} [options.loop=false] Whether a line segment will be added between the last and first line positions to make this line a loop.
- * @param {Material} [options.material=Material.ColorType] The material.
- * @param {Cartesian3[]} [options.positions] The positions.
- * @param {Object} [options.id] The user-defined object to be returned when this polyline is picked.
- * @param {DistanceDisplayCondition} [options.distanceDisplayCondition] The condition specifying at what distance from the camera that this polyline will be displayed.
- * @param {PolylineCollection} polylineCollection The renderable polyline collection.
- *
- * @see PolylineCollection
- *
- */
- function Polyline(options, polylineCollection) {
- options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- this._show = defaultValue(options.show, true);
- this._width = defaultValue(options.width, 1.0);
- this._loop = defaultValue(options.loop, false);
- this._distanceDisplayCondition = options.distanceDisplayCondition;
- this._material = options.material;
- if (!defined(this._material)) {
- this._material = Material.fromType(Material.ColorType, {
- color: new Color(1.0, 1.0, 1.0, 1.0),
- });
- }
- let positions = options.positions;
- if (!defined(positions)) {
- positions = [];
- }
- this._positions = positions;
- this._actualPositions = arrayRemoveDuplicates(
- positions,
- Cartesian3.equalsEpsilon
- );
- if (this._loop && this._actualPositions.length > 2) {
- if (this._actualPositions === this._positions) {
- this._actualPositions = positions.slice();
- }
- this._actualPositions.push(Cartesian3.clone(this._actualPositions[0]));
- }
- this._length = this._actualPositions.length;
- this._id = options.id;
- let modelMatrix;
- if (defined(polylineCollection)) {
- modelMatrix = Matrix4.clone(polylineCollection.modelMatrix);
- }
- this._modelMatrix = modelMatrix;
- this._segments = PolylinePipeline.wrapLongitude(
- this._actualPositions,
- modelMatrix
- );
- this._actualLength = undefined;
- // eslint-disable-next-line no-use-before-define
- this._propertiesChanged = new Uint32Array(NUMBER_OF_PROPERTIES);
- this._polylineCollection = polylineCollection;
- this._dirty = false;
- this._pickId = undefined;
- this._boundingVolume = BoundingSphere.fromPoints(this._actualPositions);
- this._boundingVolumeWC = BoundingSphere.transform(
- this._boundingVolume,
- this._modelMatrix
- );
- this._boundingVolume2D = new BoundingSphere(); // modified in PolylineCollection
- }
- const POSITION_INDEX = (Polyline.POSITION_INDEX = 0);
- const SHOW_INDEX = (Polyline.SHOW_INDEX = 1);
- const WIDTH_INDEX = (Polyline.WIDTH_INDEX = 2);
- const MATERIAL_INDEX = (Polyline.MATERIAL_INDEX = 3);
- const POSITION_SIZE_INDEX = (Polyline.POSITION_SIZE_INDEX = 4);
- const DISTANCE_DISPLAY_CONDITION = (Polyline.DISTANCE_DISPLAY_CONDITION = 5);
- const NUMBER_OF_PROPERTIES = (Polyline.NUMBER_OF_PROPERTIES = 6);
- function makeDirty(polyline, propertyChanged) {
- ++polyline._propertiesChanged[propertyChanged];
- const polylineCollection = polyline._polylineCollection;
- if (defined(polylineCollection)) {
- polylineCollection._updatePolyline(polyline, propertyChanged);
- polyline._dirty = true;
- }
- }
- Object.defineProperties(Polyline.prototype, {
- /**
- * Determines if this polyline will be shown. Use this to hide or show a polyline, instead
- * of removing it and re-adding it to the collection.
- * @memberof Polyline.prototype
- * @type {Boolean}
- */
- show: {
- get: function () {
- return this._show;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(value)) {
- throw new DeveloperError("value is required.");
- }
- //>>includeEnd('debug');
- if (value !== this._show) {
- this._show = value;
- makeDirty(this, SHOW_INDEX);
- }
- },
- },
- /**
- * Gets or sets the positions of the polyline.
- * @memberof Polyline.prototype
- * @type {Cartesian3[]}
- * @example
- * polyline.positions = Cesium.Cartesian3.fromDegreesArray([
- * 0.0, 0.0,
- * 10.0, 0.0,
- * 0.0, 20.0
- * ]);
- */
- positions: {
- get: function () {
- return this._positions;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(value)) {
- throw new DeveloperError("value is required.");
- }
- //>>includeEnd('debug');
- let positions = arrayRemoveDuplicates(value, Cartesian3.equalsEpsilon);
- if (this._loop && positions.length > 2) {
- if (positions === value) {
- positions = value.slice();
- }
- positions.push(Cartesian3.clone(positions[0]));
- }
- if (
- this._actualPositions.length !== positions.length ||
- this._actualPositions.length !== this._length
- ) {
- makeDirty(this, POSITION_SIZE_INDEX);
- }
- this._positions = value;
- this._actualPositions = positions;
- this._length = positions.length;
- this._boundingVolume = BoundingSphere.fromPoints(
- this._actualPositions,
- this._boundingVolume
- );
- this._boundingVolumeWC = BoundingSphere.transform(
- this._boundingVolume,
- this._modelMatrix,
- this._boundingVolumeWC
- );
- makeDirty(this, POSITION_INDEX);
- this.update();
- },
- },
- /**
- * Gets or sets the surface appearance of the polyline. This can be one of several built-in {@link Material} objects or a custom material, scripted with
- * {@link https://github.com/CesiumGS/cesium/wiki/Fabric|Fabric}.
- * @memberof Polyline.prototype
- * @type {Material}
- */
- material: {
- get: function () {
- return this._material;
- },
- set: function (material) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(material)) {
- throw new DeveloperError("material is required.");
- }
- //>>includeEnd('debug');
- if (this._material !== material) {
- this._material = material;
- makeDirty(this, MATERIAL_INDEX);
- }
- },
- },
- /**
- * Gets or sets the width of the polyline.
- * @memberof Polyline.prototype
- * @type {Number}
- */
- width: {
- get: function () {
- return this._width;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug)
- if (!defined(value)) {
- throw new DeveloperError("value is required.");
- }
- //>>includeEnd('debug');
- const width = this._width;
- if (value !== width) {
- this._width = value;
- makeDirty(this, WIDTH_INDEX);
- }
- },
- },
- /**
- * Gets or sets whether a line segment will be added between the first and last polyline positions.
- * @memberof Polyline.prototype
- * @type {Boolean}
- */
- loop: {
- get: function () {
- return this._loop;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug)
- if (!defined(value)) {
- throw new DeveloperError("value is required.");
- }
- //>>includeEnd('debug');
- if (value !== this._loop) {
- let positions = this._actualPositions;
- if (value) {
- if (
- positions.length > 2 &&
- !Cartesian3.equals(positions[0], positions[positions.length - 1])
- ) {
- if (positions.length === this._positions.length) {
- this._actualPositions = positions = this._positions.slice();
- }
- positions.push(Cartesian3.clone(positions[0]));
- }
- } else if (
- positions.length > 2 &&
- Cartesian3.equals(positions[0], positions[positions.length - 1])
- ) {
- if (positions.length - 1 === this._positions.length) {
- this._actualPositions = this._positions;
- } else {
- positions.pop();
- }
- }
- this._loop = value;
- makeDirty(this, POSITION_SIZE_INDEX);
- }
- },
- },
- /**
- * Gets or sets the user-defined value returned when the polyline is picked.
- * @memberof Polyline.prototype
- * @type {*}
- */
- id: {
- get: function () {
- return this._id;
- },
- set: function (value) {
- this._id = value;
- if (defined(this._pickId)) {
- this._pickId.object.id = value;
- }
- },
- },
- /**
- * @private
- */
- pickId: {
- get: function () {
- return this._pickId;
- },
- },
- /**
- * Gets the destruction status of this polyline
- * @memberof Polyline.prototype
- * @type {Boolean}
- * @default false
- * @private
- */
- isDestroyed: {
- get: function () {
- return !defined(this._polylineCollection);
- },
- },
- /**
- * Gets or sets the condition specifying at what distance from the camera that this polyline will be displayed.
- * @memberof Polyline.prototype
- * @type {DistanceDisplayCondition}
- * @default undefined
- */
- distanceDisplayCondition: {
- get: function () {
- return this._distanceDisplayCondition;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (defined(value) && value.far <= value.near) {
- throw new DeveloperError(
- "far distance must be greater than near distance."
- );
- }
- //>>includeEnd('debug');
- if (
- !DistanceDisplayCondition.equals(value, this._distanceDisplayCondition)
- ) {
- this._distanceDisplayCondition = DistanceDisplayCondition.clone(
- value,
- this._distanceDisplayCondition
- );
- makeDirty(this, DISTANCE_DISPLAY_CONDITION);
- }
- },
- },
- });
- /**
- * @private
- */
- Polyline.prototype.update = function () {
- let modelMatrix = Matrix4.IDENTITY;
- if (defined(this._polylineCollection)) {
- modelMatrix = this._polylineCollection.modelMatrix;
- }
- const segmentPositionsLength = this._segments.positions.length;
- const segmentLengths = this._segments.lengths;
- const positionsChanged =
- this._propertiesChanged[POSITION_INDEX] > 0 ||
- this._propertiesChanged[POSITION_SIZE_INDEX] > 0;
- if (!Matrix4.equals(modelMatrix, this._modelMatrix) || positionsChanged) {
- this._segments = PolylinePipeline.wrapLongitude(
- this._actualPositions,
- modelMatrix
- );
- this._boundingVolumeWC = BoundingSphere.transform(
- this._boundingVolume,
- modelMatrix,
- this._boundingVolumeWC
- );
- }
- this._modelMatrix = Matrix4.clone(modelMatrix, this._modelMatrix);
- if (this._segments.positions.length !== segmentPositionsLength) {
- // number of positions changed
- makeDirty(this, POSITION_SIZE_INDEX);
- } else {
- const length = segmentLengths.length;
- for (let i = 0; i < length; ++i) {
- if (segmentLengths[i] !== this._segments.lengths[i]) {
- // indices changed
- makeDirty(this, POSITION_SIZE_INDEX);
- break;
- }
- }
- }
- };
- /**
- * @private
- */
- Polyline.prototype.getPickId = function (context) {
- if (!defined(this._pickId)) {
- this._pickId = context.createPickId({
- primitive: this,
- collection: this._polylineCollection,
- id: this._id,
- });
- }
- return this._pickId;
- };
- Polyline.prototype._clean = function () {
- this._dirty = false;
- const properties = this._propertiesChanged;
- for (let k = 0; k < NUMBER_OF_PROPERTIES - 1; ++k) {
- properties[k] = 0;
- }
- };
- Polyline.prototype._destroy = function () {
- this._pickId = this._pickId && this._pickId.destroy();
- this._material = this._material && this._material.destroy();
- this._polylineCollection = undefined;
- };
- export default Polyline;
|