You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
428 lines
12 KiB
JavaScript
428 lines
12 KiB
JavaScript
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),
|
|
});
|
|
}
|
|
|
|
var 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;
|
|
|
|
var 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
|
|
}
|
|
|
|
var POSITION_INDEX = (Polyline.POSITION_INDEX = 0);
|
|
var SHOW_INDEX = (Polyline.SHOW_INDEX = 1);
|
|
var WIDTH_INDEX = (Polyline.WIDTH_INDEX = 2);
|
|
var MATERIAL_INDEX = (Polyline.MATERIAL_INDEX = 3);
|
|
var POSITION_SIZE_INDEX = (Polyline.POSITION_SIZE_INDEX = 4);
|
|
var DISTANCE_DISPLAY_CONDITION = (Polyline.DISTANCE_DISPLAY_CONDITION = 5);
|
|
var NUMBER_OF_PROPERTIES = (Polyline.NUMBER_OF_PROPERTIES = 6);
|
|
|
|
function makeDirty(polyline, propertyChanged) {
|
|
++polyline._propertiesChanged[propertyChanged];
|
|
var 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');
|
|
|
|
var 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');
|
|
|
|
var 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) {
|
|
var 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 () {
|
|
var modelMatrix = Matrix4.IDENTITY;
|
|
if (defined(this._polylineCollection)) {
|
|
modelMatrix = this._polylineCollection.modelMatrix;
|
|
}
|
|
|
|
var segmentPositionsLength = this._segments.positions.length;
|
|
var segmentLengths = this._segments.lengths;
|
|
|
|
var 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 {
|
|
var length = segmentLengths.length;
|
|
for (var 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;
|
|
var properties = this._propertiesChanged;
|
|
for (var 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;
|