123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666 |
- import BoundingRectangle from "../Core/BoundingRectangle.js";
- import Cartesian2 from "../Core/Cartesian2.js";
- import Cartesian3 from "../Core/Cartesian3.js";
- import Cartesian4 from "../Core/Cartesian4.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 NearFarScalar from "../Core/NearFarScalar.js";
- import SceneMode from "./SceneMode.js";
- import SceneTransforms from "./SceneTransforms.js";
- /**
- * A graphical point positioned in the 3D scene, that is created
- * and rendered using a {@link PointPrimitiveCollection}. A point is created and its initial
- * properties are set by calling {@link PointPrimitiveCollection#add}.
- *
- * @alias PointPrimitive
- *
- * @performance Reading a property, e.g., {@link PointPrimitive#show}, is constant time.
- * Assigning to a property is constant time but results in
- * CPU to GPU traffic when {@link PointPrimitiveCollection#update} is called. The per-pointPrimitive traffic is
- * the same regardless of how many properties were updated. If most pointPrimitives in a collection need to be
- * updated, it may be more efficient to clear the collection with {@link PointPrimitiveCollection#removeAll}
- * and add new pointPrimitives instead of modifying each one.
- *
- * @exception {DeveloperError} scaleByDistance.far must be greater than scaleByDistance.near
- * @exception {DeveloperError} translucencyByDistance.far must be greater than translucencyByDistance.near
- * @exception {DeveloperError} distanceDisplayCondition.far must be greater than distanceDisplayCondition.near
- *
- * @see PointPrimitiveCollection
- * @see PointPrimitiveCollection#add
- *
- * @internalConstructor
- * @class
- *
- * @demo {@link https://sandcastle.cesium.com/index.html?src=Points.html|Cesium Sandcastle Points Demo}
- */
- function PointPrimitive(options, pointPrimitiveCollection) {
- options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- //>>includeStart('debug', pragmas.debug);
- if (
- defined(options.disableDepthTestDistance) &&
- options.disableDepthTestDistance < 0.0
- ) {
- throw new DeveloperError(
- "disableDepthTestDistance must be greater than or equal to 0.0."
- );
- }
- //>>includeEnd('debug');
- let translucencyByDistance = options.translucencyByDistance;
- let scaleByDistance = options.scaleByDistance;
- let distanceDisplayCondition = options.distanceDisplayCondition;
- if (defined(translucencyByDistance)) {
- //>>includeStart('debug', pragmas.debug);
- if (translucencyByDistance.far <= translucencyByDistance.near) {
- throw new DeveloperError(
- "translucencyByDistance.far must be greater than translucencyByDistance.near."
- );
- }
- //>>includeEnd('debug');
- translucencyByDistance = NearFarScalar.clone(translucencyByDistance);
- }
- if (defined(scaleByDistance)) {
- //>>includeStart('debug', pragmas.debug);
- if (scaleByDistance.far <= scaleByDistance.near) {
- throw new DeveloperError(
- "scaleByDistance.far must be greater than scaleByDistance.near."
- );
- }
- //>>includeEnd('debug');
- scaleByDistance = NearFarScalar.clone(scaleByDistance);
- }
- if (defined(distanceDisplayCondition)) {
- //>>includeStart('debug', pragmas.debug);
- if (distanceDisplayCondition.far <= distanceDisplayCondition.near) {
- throw new DeveloperError(
- "distanceDisplayCondition.far must be greater than distanceDisplayCondition.near."
- );
- }
- //>>includeEnd('debug');
- distanceDisplayCondition = DistanceDisplayCondition.clone(
- distanceDisplayCondition
- );
- }
- this._show = defaultValue(options.show, true);
- this._position = Cartesian3.clone(
- defaultValue(options.position, Cartesian3.ZERO)
- );
- this._actualPosition = Cartesian3.clone(this._position); // For columbus view and 2D
- this._color = Color.clone(defaultValue(options.color, Color.WHITE));
- this._outlineColor = Color.clone(
- defaultValue(options.outlineColor, Color.TRANSPARENT)
- );
- this._outlineWidth = defaultValue(options.outlineWidth, 0.0);
- this._pixelSize = defaultValue(options.pixelSize, 10.0);
- this._scaleByDistance = scaleByDistance;
- this._translucencyByDistance = translucencyByDistance;
- this._distanceDisplayCondition = distanceDisplayCondition;
- this._disableDepthTestDistance = defaultValue(
- options.disableDepthTestDistance,
- 0.0
- );
- this._id = options.id;
- this._collection = defaultValue(options.collection, pointPrimitiveCollection);
- this._clusterShow = true;
- this._pickId = undefined;
- this._pointPrimitiveCollection = pointPrimitiveCollection;
- this._dirty = false;
- this._index = -1; //Used only by PointPrimitiveCollection
- }
- const SHOW_INDEX = (PointPrimitive.SHOW_INDEX = 0);
- const POSITION_INDEX = (PointPrimitive.POSITION_INDEX = 1);
- const COLOR_INDEX = (PointPrimitive.COLOR_INDEX = 2);
- const OUTLINE_COLOR_INDEX = (PointPrimitive.OUTLINE_COLOR_INDEX = 3);
- const OUTLINE_WIDTH_INDEX = (PointPrimitive.OUTLINE_WIDTH_INDEX = 4);
- const PIXEL_SIZE_INDEX = (PointPrimitive.PIXEL_SIZE_INDEX = 5);
- const SCALE_BY_DISTANCE_INDEX = (PointPrimitive.SCALE_BY_DISTANCE_INDEX = 6);
- const TRANSLUCENCY_BY_DISTANCE_INDEX = (PointPrimitive.TRANSLUCENCY_BY_DISTANCE_INDEX = 7);
- const DISTANCE_DISPLAY_CONDITION_INDEX = (PointPrimitive.DISTANCE_DISPLAY_CONDITION_INDEX = 8);
- const DISABLE_DEPTH_DISTANCE_INDEX = (PointPrimitive.DISABLE_DEPTH_DISTANCE_INDEX = 9);
- PointPrimitive.NUMBER_OF_PROPERTIES = 10;
- function makeDirty(pointPrimitive, propertyChanged) {
- const pointPrimitiveCollection = pointPrimitive._pointPrimitiveCollection;
- if (defined(pointPrimitiveCollection)) {
- pointPrimitiveCollection._updatePointPrimitive(
- pointPrimitive,
- propertyChanged
- );
- pointPrimitive._dirty = true;
- }
- }
- Object.defineProperties(PointPrimitive.prototype, {
- /**
- * Determines if this point will be shown. Use this to hide or show a point, instead
- * of removing it and re-adding it to the collection.
- * @memberof PointPrimitive.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 (this._show !== value) {
- this._show = value;
- makeDirty(this, SHOW_INDEX);
- }
- },
- },
- /**
- * Gets or sets the Cartesian position of this point.
- * @memberof PointPrimitive.prototype
- * @type {Cartesian3}
- */
- position: {
- get: function () {
- return this._position;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug)
- if (!defined(value)) {
- throw new DeveloperError("value is required.");
- }
- //>>includeEnd('debug');
- const position = this._position;
- if (!Cartesian3.equals(position, value)) {
- Cartesian3.clone(value, position);
- Cartesian3.clone(value, this._actualPosition);
- makeDirty(this, POSITION_INDEX);
- }
- },
- },
- /**
- * Gets or sets near and far scaling properties of a point based on the point's distance from the camera.
- * A point's scale will interpolate between the {@link NearFarScalar#nearValue} and
- * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds
- * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
- * Outside of these ranges the point's scale remains clamped to the nearest bound. This scale
- * multiplies the pixelSize and outlineWidth to affect the total size of the point. If undefined,
- * scaleByDistance will be disabled.
- * @memberof PointPrimitive.prototype
- * @type {NearFarScalar}
- *
- * @example
- * // Example 1.
- * // Set a pointPrimitive's scaleByDistance to scale to 15 when the
- * // camera is 1500 meters from the pointPrimitive and disappear as
- * // the camera distance approaches 8.0e6 meters.
- * p.scaleByDistance = new Cesium.NearFarScalar(1.5e2, 15, 8.0e6, 0.0);
- *
- * @example
- * // Example 2.
- * // disable scaling by distance
- * p.scaleByDistance = undefined;
- */
- scaleByDistance: {
- get: function () {
- return this._scaleByDistance;
- },
- 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');
- const scaleByDistance = this._scaleByDistance;
- if (!NearFarScalar.equals(scaleByDistance, value)) {
- this._scaleByDistance = NearFarScalar.clone(value, scaleByDistance);
- makeDirty(this, SCALE_BY_DISTANCE_INDEX);
- }
- },
- },
- /**
- * Gets or sets near and far translucency properties of a point based on the point's distance from the camera.
- * A point's translucency will interpolate between the {@link NearFarScalar#nearValue} and
- * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds
- * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
- * Outside of these ranges the point's translucency remains clamped to the nearest bound. If undefined,
- * translucencyByDistance will be disabled.
- * @memberof PointPrimitive.prototype
- * @type {NearFarScalar}
- *
- * @example
- * // Example 1.
- * // Set a point's translucency to 1.0 when the
- * // camera is 1500 meters from the point and disappear as
- * // the camera distance approaches 8.0e6 meters.
- * p.translucencyByDistance = new Cesium.NearFarScalar(1.5e2, 1.0, 8.0e6, 0.0);
- *
- * @example
- * // Example 2.
- * // disable translucency by distance
- * p.translucencyByDistance = undefined;
- */
- translucencyByDistance: {
- get: function () {
- return this._translucencyByDistance;
- },
- 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');
- const translucencyByDistance = this._translucencyByDistance;
- if (!NearFarScalar.equals(translucencyByDistance, value)) {
- this._translucencyByDistance = NearFarScalar.clone(
- value,
- translucencyByDistance
- );
- makeDirty(this, TRANSLUCENCY_BY_DISTANCE_INDEX);
- }
- },
- },
- /**
- * Gets or sets the inner size of the point in pixels.
- * @memberof PointPrimitive.prototype
- * @type {Number}
- */
- pixelSize: {
- get: function () {
- return this._pixelSize;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(value)) {
- throw new DeveloperError("value is required.");
- }
- //>>includeEnd('debug');
- if (this._pixelSize !== value) {
- this._pixelSize = value;
- makeDirty(this, PIXEL_SIZE_INDEX);
- }
- },
- },
- /**
- * Gets or sets the inner color of the point.
- * The red, green, blue, and alpha values are indicated by <code>value</code>'s <code>red</code>, <code>green</code>,
- * <code>blue</code>, and <code>alpha</code> properties as shown in Example 1. These components range from <code>0.0</code>
- * (no intensity) to <code>1.0</code> (full intensity).
- * @memberof PointPrimitive.prototype
- * @type {Color}
- *
- * @example
- * // Example 1. Assign yellow.
- * p.color = Cesium.Color.YELLOW;
- *
- * @example
- * // Example 2. Make a pointPrimitive 50% translucent.
- * p.color = new Cesium.Color(1.0, 1.0, 1.0, 0.5);
- */
- color: {
- get: function () {
- return this._color;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(value)) {
- throw new DeveloperError("value is required.");
- }
- //>>includeEnd('debug');
- const color = this._color;
- if (!Color.equals(color, value)) {
- Color.clone(value, color);
- makeDirty(this, COLOR_INDEX);
- }
- },
- },
- /**
- * Gets or sets the outline color of the point.
- * @memberof PointPrimitive.prototype
- * @type {Color}
- */
- outlineColor: {
- get: function () {
- return this._outlineColor;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(value)) {
- throw new DeveloperError("value is required.");
- }
- //>>includeEnd('debug');
- const outlineColor = this._outlineColor;
- if (!Color.equals(outlineColor, value)) {
- Color.clone(value, outlineColor);
- makeDirty(this, OUTLINE_COLOR_INDEX);
- }
- },
- },
- /**
- * Gets or sets the outline width in pixels. This width adds to pixelSize,
- * increasing the total size of the point.
- * @memberof PointPrimitive.prototype
- * @type {Number}
- */
- outlineWidth: {
- get: function () {
- return this._outlineWidth;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(value)) {
- throw new DeveloperError("value is required.");
- }
- //>>includeEnd('debug');
- if (this._outlineWidth !== value) {
- this._outlineWidth = value;
- makeDirty(this, OUTLINE_WIDTH_INDEX);
- }
- },
- },
- /**
- * Gets or sets the condition specifying at what distance from the camera that this point will be displayed.
- * @memberof PointPrimitive.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 must be greater than near");
- }
- //>>includeEnd('debug');
- if (
- !DistanceDisplayCondition.equals(this._distanceDisplayCondition, value)
- ) {
- this._distanceDisplayCondition = DistanceDisplayCondition.clone(
- value,
- this._distanceDisplayCondition
- );
- makeDirty(this, DISTANCE_DISPLAY_CONDITION_INDEX);
- }
- },
- },
- /**
- * Gets or sets the distance from the camera at which to disable the depth test to, for example, prevent clipping against terrain.
- * When set to zero, the depth test is always applied. When set to Number.POSITIVE_INFINITY, the depth test is never applied.
- * @memberof PointPrimitive.prototype
- * @type {Number}
- * @default 0.0
- */
- disableDepthTestDistance: {
- get: function () {
- return this._disableDepthTestDistance;
- },
- set: function (value) {
- if (this._disableDepthTestDistance !== value) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(value) || value < 0.0) {
- throw new DeveloperError(
- "disableDepthTestDistance must be greater than or equal to 0.0."
- );
- }
- //>>includeEnd('debug');
- this._disableDepthTestDistance = value;
- makeDirty(this, DISABLE_DEPTH_DISTANCE_INDEX);
- }
- },
- },
- /**
- * Gets or sets the user-defined value returned when the point is picked.
- * @memberof PointPrimitive.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;
- },
- },
- /**
- * Determines whether or not this point will be shown or hidden because it was clustered.
- * @memberof PointPrimitive.prototype
- * @type {Boolean}
- * @private
- */
- clusterShow: {
- get: function () {
- return this._clusterShow;
- },
- set: function (value) {
- if (this._clusterShow !== value) {
- this._clusterShow = value;
- makeDirty(this, SHOW_INDEX);
- }
- },
- },
- });
- PointPrimitive.prototype.getPickId = function (context) {
- if (!defined(this._pickId)) {
- this._pickId = context.createPickId({
- primitive: this,
- collection: this._collection,
- id: this._id,
- });
- }
- return this._pickId;
- };
- PointPrimitive.prototype._getActualPosition = function () {
- return this._actualPosition;
- };
- PointPrimitive.prototype._setActualPosition = function (value) {
- Cartesian3.clone(value, this._actualPosition);
- makeDirty(this, POSITION_INDEX);
- };
- const tempCartesian3 = new Cartesian4();
- PointPrimitive._computeActualPosition = function (
- position,
- frameState,
- modelMatrix
- ) {
- if (frameState.mode === SceneMode.SCENE3D) {
- return position;
- }
- Matrix4.multiplyByPoint(modelMatrix, position, tempCartesian3);
- return SceneTransforms.computeActualWgs84Position(frameState, tempCartesian3);
- };
- const scratchCartesian4 = new Cartesian4();
- // This function is basically a stripped-down JavaScript version of PointPrimitiveCollectionVS.glsl
- PointPrimitive._computeScreenSpacePosition = function (
- modelMatrix,
- position,
- scene,
- result
- ) {
- // Model to world coordinates
- const positionWorld = Matrix4.multiplyByVector(
- modelMatrix,
- Cartesian4.fromElements(
- position.x,
- position.y,
- position.z,
- 1,
- scratchCartesian4
- ),
- scratchCartesian4
- );
- const positionWC = SceneTransforms.wgs84ToWindowCoordinates(
- scene,
- positionWorld,
- result
- );
- return positionWC;
- };
- /**
- * Computes the screen-space position of the point's origin.
- * The screen space origin is the top, left corner of the canvas; <code>x</code> increases from
- * left to right, and <code>y</code> increases from top to bottom.
- *
- * @param {Scene} scene The scene.
- * @param {Cartesian2} [result] The object onto which to store the result.
- * @returns {Cartesian2} The screen-space position of the point.
- *
- * @exception {DeveloperError} PointPrimitive must be in a collection.
- *
- * @example
- * console.log(p.computeScreenSpacePosition(scene).toString());
- */
- PointPrimitive.prototype.computeScreenSpacePosition = function (scene, result) {
- const pointPrimitiveCollection = this._pointPrimitiveCollection;
- if (!defined(result)) {
- result = new Cartesian2();
- }
- //>>includeStart('debug', pragmas.debug);
- if (!defined(pointPrimitiveCollection)) {
- throw new DeveloperError("PointPrimitive must be in a collection.");
- }
- if (!defined(scene)) {
- throw new DeveloperError("scene is required.");
- }
- //>>includeEnd('debug');
- const modelMatrix = pointPrimitiveCollection.modelMatrix;
- const windowCoordinates = PointPrimitive._computeScreenSpacePosition(
- modelMatrix,
- this._actualPosition,
- scene,
- result
- );
- if (!defined(windowCoordinates)) {
- return undefined;
- }
- windowCoordinates.y = scene.canvas.clientHeight - windowCoordinates.y;
- return windowCoordinates;
- };
- /**
- * Gets a point's screen space bounding box centered around screenSpacePosition.
- * @param {PointPrimitive} point The point to get the screen space bounding box for.
- * @param {Cartesian2} screenSpacePosition The screen space center of the label.
- * @param {BoundingRectangle} [result] The object onto which to store the result.
- * @returns {BoundingRectangle} The screen space bounding box.
- *
- * @private
- */
- PointPrimitive.getScreenSpaceBoundingBox = function (
- point,
- screenSpacePosition,
- result
- ) {
- const size = point.pixelSize;
- const halfSize = size * 0.5;
- const x = screenSpacePosition.x - halfSize;
- const y = screenSpacePosition.y - halfSize;
- const width = size;
- const height = size;
- if (!defined(result)) {
- result = new BoundingRectangle();
- }
- result.x = x;
- result.y = y;
- result.width = width;
- result.height = height;
- return result;
- };
- /**
- * Determines if this point equals another point. Points are equal if all their properties
- * are equal. Points in different collections can be equal.
- *
- * @param {PointPrimitive} other The point to compare for equality.
- * @returns {Boolean} <code>true</code> if the points are equal; otherwise, <code>false</code>.
- */
- PointPrimitive.prototype.equals = function (other) {
- return (
- this === other ||
- (defined(other) &&
- this._id === other._id &&
- Cartesian3.equals(this._position, other._position) &&
- Color.equals(this._color, other._color) &&
- this._pixelSize === other._pixelSize &&
- this._outlineWidth === other._outlineWidth &&
- this._show === other._show &&
- Color.equals(this._outlineColor, other._outlineColor) &&
- NearFarScalar.equals(this._scaleByDistance, other._scaleByDistance) &&
- NearFarScalar.equals(
- this._translucencyByDistance,
- other._translucencyByDistance
- ) &&
- DistanceDisplayCondition.equals(
- this._distanceDisplayCondition,
- other._distanceDisplayCondition
- ) &&
- this._disableDepthTestDistance === other._disableDepthTestDistance)
- );
- };
- PointPrimitive.prototype._destroy = function () {
- this._pickId = this._pickId && this._pickId.destroy();
- this._pointPrimitiveCollection = undefined;
- };
- export default PointPrimitive;
|