Source: src/js/models/maps/assets/CesiumTerrain.js

"use strict";

define([
  "jquery",
  "underscore",
  "backbone",
  "cesium",
  "models/maps/assets/MapAsset",
], function ($, _, Backbone, Cesium, MapAsset) {
  /**
   * @classdesc A CesiumTerrain Model comprises the information required to fetch 3D
   * terrain, such as mountain peaks and valleys, to display in Cesium. A terrain model
   * also contains metadata about the terrain source data, such as an attribution and a
   * description.
   * @classcategory Models/Maps/Assets
   * @class CesiumTerrain
   * @name CesiumTerrain
   * @extends MapAsset
   * @since 2.18.0
   * @constructor
   */
  var CesiumTerrain = MapAsset.extend(
    /** @lends CesiumTerrain.prototype */ {
      /**
       * The name of this type of model
       * @type {string}
       */
      type: "CesiumTerrain",

      /**
       * Options that are supported for creating terrain in Cesium. Any properties
       * provided here are passed to the Cesium constructor function for the Terrain
       * Provider, so other properties that are documented in Cesium are also supported.
       * See `options` here:
       * {@link https://cesium.com/learn/cesiumjs/ref-doc/CesiumTerrainProvider.html?classFilter=TerrainProvider}
       * @typedef {Object} CesiumTerrain#cesiumOptions
       * @property {string|number} ionAssetId - If this terrain is hosted by Cesium Ion,
       * then Ion asset ID.
       */

      /**
       * Default attributes for CesiumTerrain models
       * @name CesiumTerrain#defaults
       * @extends MapAsset#defaults
       * @type {Object}
       * @property {'CesiumTerrainProvider'} type A string indicating a Cesium Terrain
       * Provider, see
       * {@link https://cesium.com/learn/cesiumjs/ref-doc/?classFilter=TerrainProvider}
       * @property {Cesium.TerrainProvider} cesiumModel A model created and used by
       * Cesium that organizes the data to display in the Cesium Widget. See
       * {@link https://cesium.com/learn/cesiumjs/ref-doc/TerrainProvider.html}
       * @property {CesiumTerrain#cesiumOptions} cesiumOptions options are passed to the
       * function that creates the Cesium model. The properties of options are specific
       * to each type of asset
       */
      defaults: function () {
        return _.extend(this.constructor.__super__.defaults(), {
          type: "CesiumTerrainProvider",
          cesiumModel: null,
          cesiumOptions: {},
        });
      },

      /**
       * Executed when a new CesiumTerrain model is created.
       * @param {Object} [attributes] The initial values of the attributes, which will
       * be set on the model.
       * @param {Object} [options] Options for the initialize function.
       */
      initialize: function (attributes, options) {
        try {
          MapAsset.prototype.initialize.call(this, attributes, options);

          this.createCesiumModel();
        } catch (error) {
          console.log(
            "There was an error initializing a CesiumTerrain model" +
              ". Error details: " +
              error,
          );
        }
      },

      /**
       * Creates a Cesium TerrainProvider that contains information about where the
       * terrain data should be requested from and how to render it in Cesium. See
       * {@link https://cesium.com/learn/cesiumjs/ref-doc/TerrainProvider.html?classFilter=terrain}
       * @param {Boolean} recreate - Set recreate to true to force the function create
       * the Cesium Model again. Otherwise, if a cesium model already exists, that is
       * returned instead.
       */
      createCesiumModel: function (recreate = false) {
        var model = this;
        var cesiumOptions = model.getCesiumOptions();
        var type = this.get("type");
        var terrainFunction = Cesium[type];

        // If the cesium model already exists, don't create it again unless specified
        if (!recreate && this.get("cesiumModel")) {
          return this.get("cesiumModel");
        }

        model.resetStatus();

        // If this tileset is a Cesium Ion resource, set the url from the
        // asset Id
        cesiumOptions.url =
          this.getCesiumURL(cesiumOptions) || cesiumOptions.url;

        if (terrainFunction && typeof terrainFunction === "function") {
          let terrain = new terrainFunction(cesiumOptions);
          terrain.readyPromise
            .then(function () {
              model.set("cesiumModel", terrain);
              model.set("status", "ready");
            })
            .otherwise(function (error) {
              model.set("status", "error");
              model.set("statusDetails", error);
            });
        } else {
          model.set("status", "error");
          model.set(
            "statusDetails",
            type + " is not a supported imagery type.",
          );
        }
      },

      /**
       * Checks whether there is an asset ID for a Cesium Ion resource and if
       * so, return the URL to the resource.
       * @returns {string} The URL to the Cesium Ion resource
       * @since 2.26.0
       */
      getCesiumURL: function () {
        try {
          const cesiumOptions = this.getCesiumOptions();
          if (!cesiumOptions || !cesiumOptions.ionAssetId) return null;
          // The Cesium Ion ID of the resource to access
          const assetId = Number(cesiumOptions.ionAssetId);
          // Options to pass to Cesium's fromAssetId function. Access token
          // needs to be set before requesting cesium ion resources
          const ionResourceOptions = {
            accessToken:
              cesiumOptions.cesiumToken ||
              MetacatUI.appModel.get("cesiumToken"),
          };
          // Create the new URL and set it on the model options
          return Cesium.IonResource.fromAssetId(assetId, ionResourceOptions);
        } catch (error) {
          console.log(
            "There was an error settings a Cesium URL in a Cesium3DTileset" +
              ". Error details: " +
              error,
          );
        }
      },

      // /**
      //  * Parses the given input into a JSON object to be set on the model.
      //  *
      //  * @param {TODO} input - The raw response object
      //  * @return {TODO} - The JSON object of all the CesiumTerrain attributes
      //  */
      // parse: function (input) {

      //   try {

      //     var modelJSON = {};

      //     return modelJSON

      //   }
      //   catch (error) {
      //     console.log(
      //       'There was an error parsing a CesiumTerrain model' +
      //       '. Error details: ' + error
      //     );
      //   }

      // },

      // /**
      //  * Overrides the default Backbone.Model.validate.function() to check if this if
      //  * the values set on this model are valid.
      //  *
      //  * @param {Object} [attrs] - A literal object of model attributes to validate.
      //  * @param {Object} [options] - A literal object of options for this validation
      //  * process
      //  *
      //  * @return {Object} - Returns a literal object with the invalid attributes and
      //  * their corresponding error message, if there are any. If there are no errors,
      //  * returns nothing.
      //  */
      // validate: function (attrs, options) {
      //   try {

      //   }
      //   catch (error) {
      //     console.log(
      //       'There was an error validating a CesiumTerrain model' +
      //       '. Error details: ' + error
      //     );
      //   }
      // },

      // /**
      //  * Creates a string using the values set on this model's attributes.
      //  * @return {string} The CesiumTerrain string
      //  */
      // serialize: function () {
      //   try {
      //     var serializedTerrain = '';

      //     return serializedTerrain;
      //   }
      //   catch (error) {
      //     console.log(
      //       'There was an error serializing a CesiumTerrain model' +
      //       '. Error details: ' + error
      //     );
      //   }
      // },
    },
  );

  return CesiumTerrain;
});