| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765 | import ApproximateTerrainHeights from "../Core/ApproximateTerrainHeights.js";import arraySlice from "../Core/arraySlice.js";import Cartesian2 from "../Core/Cartesian2.js";import Cartesian3 from "../Core/Cartesian3.js";import Color from "../Core/Color.js";import ComponentDatatype from "../Core/ComponentDatatype.js";import defaultValue from "../Core/defaultValue.js";import defer from "../Core/defer.js";import defined from "../Core/defined.js";import destroyObject from "../Core/destroyObject.js";import Ellipsoid from "../Core/Ellipsoid.js";import FeatureDetection from "../Core/FeatureDetection.js";import IndexDatatype from "../Core/IndexDatatype.js";import OrientedBoundingBox from "../Core/OrientedBoundingBox.js";import Matrix4 from "../Core/Matrix4.js";import Rectangle from "../Core/Rectangle.js";import TaskProcessor from "../Core/TaskProcessor.js";import Buffer from "../Renderer/Buffer.js";import BufferUsage from "../Renderer/BufferUsage.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 VertexArray from "../Renderer/VertexArray.js";import PolylineCommon from "../Shaders/PolylineCommon.js";import Vector3DTileClampedPolylinesVS from "../Shaders/Vector3DTileClampedPolylinesVS.js";import Vector3DTileClampedPolylinesFS from "../Shaders/Vector3DTileClampedPolylinesFS.js";import BlendingState from "./BlendingState.js";import Cesium3DTileFeature from "./Cesium3DTileFeature.js";import ClassificationType from "./ClassificationType.js";import CullFace from "./CullFace.js";import StencilConstants from "./StencilConstants.js";import StencilFunction from "./StencilFunction.js";import StencilOperation from "./StencilOperation.js";import Vector3DTilePolylines from "./Vector3DTilePolylines.js";/** * Creates a batch of polylines as volumes with shader-adjustable width. * * @alias Vector3DTileClampedPolylines * @constructor * * @param {Object} options An object with following properties: * @param {Uint16Array} options.positions The positions of the polylines * @param {Uint32Array} options.counts The number or positions in the each polyline. * @param {Uint16Array} options.widths The width of each polyline. * @param {Number} options.minimumHeight The minimum height of the tile's region. * @param {Number} options.maximumHeight The maximum height of the tile's region. * @param {Rectangle} options.rectangle The rectangle containing the tile. * @param {Cartesian3} [options.center=Cartesian3.ZERO] The RTC center. * @param {Cesium3DTileBatchTable} options.batchTable The batch table for the tile containing the batched polylines. * @param {Uint16Array} options.batchIds The batch ids for each polyline. * @param {ClassificationType} options.classificationType The classification type. * @param {Boolean} options.keepDecodedPositions Whether to keep decoded positions in memory. * * @private */function Vector3DTileClampedPolylines(options) {  // these arrays hold data from the tile payload  // and are all released after the first update.  this._positions = options.positions;  this._widths = options.widths;  this._counts = options.counts;  this._batchIds = options.batchIds;  this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);  this._minimumHeight = options.minimumHeight;  this._maximumHeight = options.maximumHeight;  this._center = options.center;  this._rectangle = options.rectangle;  this._batchTable = options.batchTable;  this._va = undefined;  this._sp = undefined;  this._rs = undefined;  this._uniformMap = undefined;  this._command = undefined;  this._transferrableBatchIds = undefined;  this._packedBuffer = undefined;  this._minimumMaximumVectorHeights = new Cartesian2(    ApproximateTerrainHeights._defaultMinTerrainHeight,    ApproximateTerrainHeights._defaultMaxTerrainHeight  );  this._boundingVolume = OrientedBoundingBox.fromRectangle(    options.rectangle,    ApproximateTerrainHeights._defaultMinTerrainHeight,    ApproximateTerrainHeights._defaultMaxTerrainHeight,    this._ellipsoid  );  this._classificationType = options.classificationType;  this._keepDecodedPositions = options.keepDecodedPositions;  this._decodedPositions = undefined;  this._decodedPositionOffsets = undefined;  // Fat vertices - all information for each volume packed to a vec3 and 5 vec4s  this._startEllipsoidNormals = undefined;  this._endEllipsoidNormals = undefined;  this._startPositionAndHeights = undefined;  this._startFaceNormalAndVertexCornerIds = undefined;  this._endPositionAndHeights = undefined;  this._endFaceNormalAndHalfWidths = undefined;  this._vertexBatchIds = undefined;  this._indices = undefined;  this._constantColor = Color.clone(Color.WHITE);  this._highlightColor = this._constantColor;  this._trianglesLength = 0;  this._geometryByteLength = 0;  this._ready = false;  this._readyPromise = defer();  this._verticesPromise = undefined;  const that = this;  ApproximateTerrainHeights.initialize()    .then(function () {      updateMinimumMaximumHeights(that, that._rectangle, that._ellipsoid);    })    .catch(function (error) {      this._readyPromise.reject(error);    });}Object.defineProperties(Vector3DTileClampedPolylines.prototype, {  /**   * Gets the number of triangles.   *   * @memberof Vector3DTileClampedPolylines.prototype   *   * @type {Number}   * @readonly   */  trianglesLength: {    get: function () {      return this._trianglesLength;    },  },  /**   * Gets the geometry memory in bytes.   *   * @memberof Vector3DTileClampedPolylines.prototype   *   * @type {Number}   * @readonly   */  geometryByteLength: {    get: function () {      return this._geometryByteLength;    },  },  /**   * Gets a promise that resolves when the primitive is ready to render.   * @memberof Vector3DTileClampedPolylines.prototype   * @type {Promise}   * @readonly   */  readyPromise: {    get: function () {      return this._readyPromise.promise;    },  },});function updateMinimumMaximumHeights(polylines, rectangle, ellipsoid) {  const result = ApproximateTerrainHeights.getMinimumMaximumHeights(    rectangle,    ellipsoid  );  const min = result.minimumTerrainHeight;  const max = result.maximumTerrainHeight;  const minimumMaximumVectorHeights = polylines._minimumMaximumVectorHeights;  minimumMaximumVectorHeights.x = min;  minimumMaximumVectorHeights.y = max;  const obb = polylines._boundingVolume;  const rect = polylines._rectangle;  OrientedBoundingBox.fromRectangle(rect, min, max, ellipsoid, obb);}function packBuffer(polylines) {  const rectangle = polylines._rectangle;  const minimumHeight = polylines._minimumHeight;  const maximumHeight = polylines._maximumHeight;  const ellipsoid = polylines._ellipsoid;  const center = polylines._center;  const packedLength =    2 +    Rectangle.packedLength +    Ellipsoid.packedLength +    Cartesian3.packedLength;  const packedBuffer = new Float64Array(packedLength);  let offset = 0;  packedBuffer[offset++] = minimumHeight;  packedBuffer[offset++] = maximumHeight;  Rectangle.pack(rectangle, packedBuffer, offset);  offset += Rectangle.packedLength;  Ellipsoid.pack(ellipsoid, packedBuffer, offset);  offset += Ellipsoid.packedLength;  Cartesian3.pack(center, packedBuffer, offset);  return packedBuffer;}const createVerticesTaskProcessor = new TaskProcessor(  "createVectorTileClampedPolylines");const attributeLocations = {  startEllipsoidNormal: 0,  endEllipsoidNormal: 1,  startPositionAndHeight: 2,  endPositionAndHeight: 3,  startFaceNormalAndVertexCorner: 4,  endFaceNormalAndHalfWidth: 5,  a_batchId: 6,};function createVertexArray(polylines, context) {  if (defined(polylines._va)) {    return;  }  if (!defined(polylines._verticesPromise)) {    let positions = polylines._positions;    let widths = polylines._widths;    let counts = polylines._counts;    let batchIds = polylines._transferrableBatchIds;    let packedBuffer = polylines._packedBuffer;    if (!defined(packedBuffer)) {      // Copy because they may be the views on the same buffer.      positions = polylines._positions = arraySlice(positions);      widths = polylines._widths = arraySlice(widths);      counts = polylines._counts = arraySlice(counts);      batchIds = polylines._transferrableBatchIds = arraySlice(        polylines._batchIds      );      packedBuffer = polylines._packedBuffer = packBuffer(polylines);    }    const transferrableObjects = [      positions.buffer,      widths.buffer,      counts.buffer,      batchIds.buffer,      packedBuffer.buffer,    ];    const parameters = {      positions: positions.buffer,      widths: widths.buffer,      counts: counts.buffer,      batchIds: batchIds.buffer,      packedBuffer: packedBuffer.buffer,      keepDecodedPositions: polylines._keepDecodedPositions,    };    const verticesPromise = (polylines._verticesPromise = createVerticesTaskProcessor.scheduleTask(      parameters,      transferrableObjects    ));    if (!defined(verticesPromise)) {      // Postponed      return;    }    Promise.resolve(verticesPromise)      .then(function (result) {        if (polylines._keepDecodedPositions) {          polylines._decodedPositions = new Float64Array(            result.decodedPositions          );          polylines._decodedPositionOffsets = new Uint32Array(            result.decodedPositionOffsets          );        }        polylines._startEllipsoidNormals = new Float32Array(          result.startEllipsoidNormals        );        polylines._endEllipsoidNormals = new Float32Array(          result.endEllipsoidNormals        );        polylines._startPositionAndHeights = new Float32Array(          result.startPositionAndHeights        );        polylines._startFaceNormalAndVertexCornerIds = new Float32Array(          result.startFaceNormalAndVertexCornerIds        );        polylines._endPositionAndHeights = new Float32Array(          result.endPositionAndHeights        );        polylines._endFaceNormalAndHalfWidths = new Float32Array(          result.endFaceNormalAndHalfWidths        );        polylines._vertexBatchIds = new Uint16Array(result.vertexBatchIds);        const indexDatatype = result.indexDatatype;        polylines._indices =          indexDatatype === IndexDatatype.UNSIGNED_SHORT            ? new Uint16Array(result.indices)            : new Uint32Array(result.indices);        polylines._ready = true;      })      .catch(function (error) {        polylines._readyPromise.reject(error);      });  }  if (polylines._ready && !defined(polylines._va)) {    const startEllipsoidNormals = polylines._startEllipsoidNormals;    const endEllipsoidNormals = polylines._endEllipsoidNormals;    const startPositionAndHeights = polylines._startPositionAndHeights;    const endPositionAndHeights = polylines._endPositionAndHeights;    const startFaceNormalAndVertexCornerIds =      polylines._startFaceNormalAndVertexCornerIds;    const endFaceNormalAndHalfWidths = polylines._endFaceNormalAndHalfWidths;    const batchIdAttribute = polylines._vertexBatchIds;    const indices = polylines._indices;    let byteLength =      startEllipsoidNormals.byteLength + endEllipsoidNormals.byteLength;    byteLength +=      startPositionAndHeights.byteLength + endPositionAndHeights.byteLength;    byteLength +=      startFaceNormalAndVertexCornerIds.byteLength +      endFaceNormalAndHalfWidths.byteLength;    byteLength += batchIdAttribute.byteLength + indices.byteLength;    polylines._trianglesLength = indices.length / 3;    polylines._geometryByteLength = byteLength;    const startEllipsoidNormalsBuffer = Buffer.createVertexBuffer({      context: context,      typedArray: startEllipsoidNormals,      usage: BufferUsage.STATIC_DRAW,    });    const endEllipsoidNormalsBuffer = Buffer.createVertexBuffer({      context: context,      typedArray: endEllipsoidNormals,      usage: BufferUsage.STATIC_DRAW,    });    const startPositionAndHeightsBuffer = Buffer.createVertexBuffer({      context: context,      typedArray: startPositionAndHeights,      usage: BufferUsage.STATIC_DRAW,    });    const endPositionAndHeightsBuffer = Buffer.createVertexBuffer({      context: context,      typedArray: endPositionAndHeights,      usage: BufferUsage.STATIC_DRAW,    });    const startFaceNormalAndVertexCornerIdsBuffer = Buffer.createVertexBuffer({      context: context,      typedArray: startFaceNormalAndVertexCornerIds,      usage: BufferUsage.STATIC_DRAW,    });    const endFaceNormalAndHalfWidthsBuffer = Buffer.createVertexBuffer({      context: context,      typedArray: endFaceNormalAndHalfWidths,      usage: BufferUsage.STATIC_DRAW,    });    const batchIdAttributeBuffer = Buffer.createVertexBuffer({      context: context,      typedArray: batchIdAttribute,      usage: BufferUsage.STATIC_DRAW,    });    const indexBuffer = Buffer.createIndexBuffer({      context: context,      typedArray: indices,      usage: BufferUsage.STATIC_DRAW,      indexDatatype:        indices.BYTES_PER_ELEMENT === 2          ? IndexDatatype.UNSIGNED_SHORT          : IndexDatatype.UNSIGNED_INT,    });    const vertexAttributes = [      {        index: attributeLocations.startEllipsoidNormal,        vertexBuffer: startEllipsoidNormalsBuffer,        componentDatatype: ComponentDatatype.FLOAT,        componentsPerAttribute: 3,      },      {        index: attributeLocations.endEllipsoidNormal,        vertexBuffer: endEllipsoidNormalsBuffer,        componentDatatype: ComponentDatatype.FLOAT,        componentsPerAttribute: 3,      },      {        index: attributeLocations.startPositionAndHeight,        vertexBuffer: startPositionAndHeightsBuffer,        componentDatatype: ComponentDatatype.FLOAT,        componentsPerAttribute: 4,      },      {        index: attributeLocations.endPositionAndHeight,        vertexBuffer: endPositionAndHeightsBuffer,        componentDatatype: ComponentDatatype.FLOAT,        componentsPerAttribute: 4,      },      {        index: attributeLocations.startFaceNormalAndVertexCorner,        vertexBuffer: startFaceNormalAndVertexCornerIdsBuffer,        componentDatatype: ComponentDatatype.FLOAT,        componentsPerAttribute: 4,      },      {        index: attributeLocations.endFaceNormalAndHalfWidth,        vertexBuffer: endFaceNormalAndHalfWidthsBuffer,        componentDatatype: ComponentDatatype.FLOAT,        componentsPerAttribute: 4,      },      {        index: attributeLocations.a_batchId,        vertexBuffer: batchIdAttributeBuffer,        componentDatatype: ComponentDatatype.UNSIGNED_SHORT,        componentsPerAttribute: 1,      },    ];    polylines._va = new VertexArray({      context: context,      attributes: vertexAttributes,      indexBuffer: indexBuffer,    });    polylines._positions = undefined;    polylines._widths = undefined;    polylines._counts = undefined;    polylines._ellipsoid = undefined;    polylines._minimumHeight = undefined;    polylines._maximumHeight = undefined;    polylines._rectangle = undefined;    polylines._transferrableBatchIds = undefined;    polylines._packedBuffer = undefined;    polylines._startEllipsoidNormals = undefined;    polylines._endEllipsoidNormals = undefined;    polylines._startPositionAndHeights = undefined;    polylines._startFaceNormalAndVertexCornerIds = undefined;    polylines._endPositionAndHeights = undefined;    polylines._endFaceNormalAndHalfWidths = undefined;    polylines._vertexBatchIds = undefined;    polylines._indices = undefined;    polylines._readyPromise.resolve();  }}const modifiedModelViewScratch = new Matrix4();const rtcScratch = new Cartesian3();function createUniformMap(primitive, context) {  if (defined(primitive._uniformMap)) {    return;  }  primitive._uniformMap = {    u_modifiedModelView: function () {      const viewMatrix = context.uniformState.view;      Matrix4.clone(viewMatrix, modifiedModelViewScratch);      Matrix4.multiplyByPoint(        modifiedModelViewScratch,        primitive._center,        rtcScratch      );      Matrix4.setTranslation(        modifiedModelViewScratch,        rtcScratch,        modifiedModelViewScratch      );      return modifiedModelViewScratch;    },    u_highlightColor: function () {      return primitive._highlightColor;    },    u_minimumMaximumVectorHeights: function () {      return primitive._minimumMaximumVectorHeights;    },  };}function getRenderState(mask3DTiles) {  /**   * Cull front faces of each volume (relative to camera) to prevent   * classification drawing from both the front and back faces, double-draw.   * The geometry is "inverted" (inside-out winding order for the indices) but   * the vertex shader seems to re-invert so that the triangles face "out" again.   * So cull FRONT faces.   */  return RenderState.fromCache({    cull: {      enabled: true,      face: CullFace.FRONT,    },    blending: BlendingState.PRE_MULTIPLIED_ALPHA_BLEND,    depthMask: false,    stencilTest: {      enabled: mask3DTiles,      frontFunction: StencilFunction.EQUAL,      frontOperation: {        fail: StencilOperation.KEEP,        zFail: StencilOperation.KEEP,        zPass: StencilOperation.KEEP,      },      backFunction: StencilFunction.EQUAL,      backOperation: {        fail: StencilOperation.KEEP,        zFail: StencilOperation.KEEP,        zPass: StencilOperation.KEEP,      },      reference: StencilConstants.CESIUM_3D_TILE_MASK,      mask: StencilConstants.CESIUM_3D_TILE_MASK,    },  });}function createRenderStates(primitive) {  if (defined(primitive._rs)) {    return;  }  primitive._rs = getRenderState(false);  primitive._rs3DTiles = getRenderState(true);}function createShaders(primitive, context) {  if (defined(primitive._sp)) {    return;  }  const batchTable = primitive._batchTable;  const vsSource = batchTable.getVertexShaderCallback(    false,    "a_batchId",    undefined  )(Vector3DTileClampedPolylinesVS);  const fsSource = batchTable.getFragmentShaderCallback(    false,    undefined,    true  )(Vector3DTileClampedPolylinesFS);  const vs = new ShaderSource({    defines: [      "VECTOR_TILE",      !FeatureDetection.isInternetExplorer() ? "CLIP_POLYLINE" : "",    ],    sources: [PolylineCommon, vsSource],  });  const fs = new ShaderSource({    defines: ["VECTOR_TILE"],    sources: [fsSource],  });  primitive._sp = ShaderProgram.fromCache({    context: context,    vertexShaderSource: vs,    fragmentShaderSource: fs,    attributeLocations: attributeLocations,  });}function queueCommands(primitive, frameState) {  let command = primitive._command;  if (!defined(primitive._command)) {    const uniformMap = primitive._batchTable.getUniformMapCallback()(      primitive._uniformMap    );    command = primitive._command = new DrawCommand({      owner: primitive,      vertexArray: primitive._va,      renderState: primitive._rs,      shaderProgram: primitive._sp,      uniformMap: uniformMap,      boundingVolume: primitive._boundingVolume,      pass: Pass.TERRAIN_CLASSIFICATION,      pickId: primitive._batchTable.getPickId(),    });    const derivedTilesetCommand = DrawCommand.shallowClone(      command,      command.derivedCommands.tileset    );    derivedTilesetCommand.renderState = primitive._rs3DTiles;    derivedTilesetCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;    command.derivedCommands.tileset = derivedTilesetCommand;  }  const classificationType = primitive._classificationType;  if (    classificationType === ClassificationType.TERRAIN ||    classificationType === ClassificationType.BOTH  ) {    frameState.commandList.push(command);  }  if (    classificationType === ClassificationType.CESIUM_3D_TILE ||    classificationType === ClassificationType.BOTH  ) {    frameState.commandList.push(command.derivedCommands.tileset);  }}/** * Get the polyline positions for the given feature. * * @param {Number} batchId The batch ID of the feature. */Vector3DTileClampedPolylines.prototype.getPositions = function (batchId) {  return Vector3DTilePolylines.getPolylinePositions(this, batchId);};/** * Creates features for each polyline and places it at the batch id index of features. * * @param {Vector3DTileContent} content The vector tile content. * @param {Cesium3DTileFeature[]} features An array of features where the polygon features will be placed. */Vector3DTileClampedPolylines.prototype.createFeatures = function (  content,  features) {  const batchIds = this._batchIds;  const length = batchIds.length;  for (let i = 0; i < length; ++i) {    const batchId = batchIds[i];    features[batchId] = new Cesium3DTileFeature(content, batchId);  }};/** * Colors the entire tile when enabled is true. The resulting color will be (polyline batch table color * color). * * @param {Boolean} enabled Whether to enable debug coloring. * @param {Color} color The debug color. */Vector3DTileClampedPolylines.prototype.applyDebugSettings = function (  enabled,  color) {  this._highlightColor = enabled ? color : this._constantColor;};function clearStyle(polygons, features) {  const batchIds = polygons._batchIds;  const length = batchIds.length;  for (let i = 0; i < length; ++i) {    const batchId = batchIds[i];    const feature = features[batchId];    feature.show = true;    feature.color = Color.WHITE;  }}const scratchColor = new Color();const DEFAULT_COLOR_VALUE = Color.WHITE;const DEFAULT_SHOW_VALUE = true;/** * Apply a style to the content. * * @param {Cesium3DTileStyle} style The style. * @param {Cesium3DTileFeature[]} features The dictionary of features. */Vector3DTileClampedPolylines.prototype.applyStyle = function (style, features) {  if (!defined(style)) {    clearStyle(this, features);    return;  }  const batchIds = this._batchIds;  const length = batchIds.length;  for (let i = 0; i < length; ++i) {    const batchId = batchIds[i];    const feature = features[batchId];    feature.color = defined(style.color)      ? style.color.evaluateColor(feature, scratchColor)      : DEFAULT_COLOR_VALUE;    feature.show = defined(style.show)      ? style.show.evaluate(feature)      : DEFAULT_SHOW_VALUE;  }};/** * Updates the batches and queues the commands for rendering. * * @param {FrameState} frameState The current frame state. */Vector3DTileClampedPolylines.prototype.update = function (frameState) {  const context = frameState.context;  createVertexArray(this, context);  createUniformMap(this, context);  createShaders(this, context);  createRenderStates(this);  if (!this._ready) {    return;  }  const passes = frameState.passes;  if (passes.render || passes.pick) {    queueCommands(this, frameState);  }};/** * Returns true if this object was destroyed; otherwise, false. * <p> * 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. * </p> * * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>. */Vector3DTileClampedPolylines.prototype.isDestroyed = function () {  return false;};/** * 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. * <p> * 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. * </p> * * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called. */Vector3DTileClampedPolylines.prototype.destroy = function () {  this._va = this._va && this._va.destroy();  this._sp = this._sp && this._sp.destroy();  return destroyObject(this);};export default Vector3DTileClampedPolylines;
 |