import type Extent from "./Extent.js";
import type BaseGeometry from "./Geometry.js";
import type Point from "./Point.js";
import type Polygon from "./Polygon.js";
import type MeshComponent from "./support/MeshComponent.js";
import type MeshTransform from "./support/MeshTransform.js";
import type MeshVertexAttributes from "./support/MeshVertexAttributes.js";
import type { ClonableMixin } from "../core/Clonable.js";
import type { LoadableMixin, LoadableMixinProperties } from "../core/Loadable.js";
import type { EsriPromiseMixin } from "../core/Promise.js";
import type { MeshVertexSpaceUnion } from "./types.js";
import type { MeshComponentProperties } from "./support/MeshComponent.js";
import type { MeshMaterialProperties } from "./support/MeshMaterial.js";
import type { CreateBoxParameters, CreateCylinderParameters, CreateSphereParameters, CreatePlaneParameters, RotateParameters, CenterAtParameters, ScaleParameters, CreateFromGLTFParameters, ExportGLTFOptions } from "./support/meshUtils/types.js";
import type { MeshLocalVertexSpaceProperties } from "./support/MeshLocalVertexSpace.js";
import type { MeshGeoreferencedVertexSpaceProperties } from "./support/MeshGeoreferencedVertexSpace.js";
import type { MeshTransformProperties } from "./support/MeshTransform.js";
import type { MeshVertexAttributesProperties } from "./support/MeshVertexAttributes.js";
import type { GeometryProperties as BaseGeometryProperties } from "./Geometry.js";

export interface MeshProperties extends BaseGeometryProperties, LoadableMixinProperties {
  /**
   * An array of mesh components that can be used to apply materials
   * to different regions of the same mesh. There are three common
   * usage patterns for components.
   *
   * 1. **Specify a material for the whole mesh.** In this case, use a single
   *    component with only a material (leaving faces as `null`).
   * 2. **Reuse vertex attributes.** When modeling continuous surfaces,
   *    it can be convenient to only specify vertices once and then
   *    simply refer to them. In this case, use a single component
   *    with faces set to index the vertex attributes that form
   *    triangles.
   * 3. **Specify multiple materials for the same mesh.** In this case,
   *    use multiple components with faces that determine to which region
   *    of the mesh the material of the component applies.
   */
  components?: MeshComponentProperties[] | null;
  /**
   * Additional local transformation of the mesh vertices. The transform is ignored if the [vertexSpace)(#vertexSpace)
   * is of type [georeferenced](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshGeoreferencedVertexSpace.html) and does not specify
   * an [MeshGeoreferencedVertexSpace.origin](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshGeoreferencedVertexSpace.html#origin).
   */
  transform?: MeshTransformProperties | null;
  /**
   * Object describing the attributes of each vertex of the mesh. Vertex attributes
   * are flat numerical arrays that describe the position (mandatory), normal (used for
   * lighting calculations and shading) and UV (used for mapping material images to the
   * mesh surface) for each vertex.
   *
   * Vertex attributes can be addressed by indices specified in the components
   * [MeshComponent.faces](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshComponent.html#faces) property. If the
   * mesh does not contain any components, or if a component does not specify any faces,
   * then the vertex attributes are interpreted as if each consecutive vertex triple
   * makes up a triangle.
   *
   * @example
   * let mesh = new Mesh({ spatialReference: SpatialReference.WebMercator });
   *
   * // Specify vertices for two triangles that make up a square
   * // around a provided point. UV coordinates are set up to cover the square
   * // from (0, 0) to (1, 1) from corner to corner.
   * mesh.vertexAttributes = {
   *   position: [
   *     pt.x - 10, pt.y - 10, 100,
   *     pt.x + 10, pt.y - 10, 100,
   *     pt.x + 10, pt.y + 10, 100,
   *
   *     pt.x - 10, pt.y - 10, 100,
   *     pt.x + 10, pt.y + 10, 100,
   *     pt.x - 10, pt.y + 10, 100
   *   ],
   *   uv: [
   *     0, 0,
   *     1, 0,
   *     1, 1,
   *
   *     0, 0,
   *     1, 1,
   *     0, 1
   *   ]
   * };
   */
  vertexAttributes?: MeshVertexAttributesProperties;
  /** The vertex space of the mesh. See [mesh API](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#mesh-api) for details. */
  vertexSpace?: ((MeshGeoreferencedVertexSpaceProperties & { type: "georeferenced" }) | (MeshLocalVertexSpaceProperties & { type: "local" }));
}

/**
 * A mesh is a general, client-side 3D [Geometry](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Geometry.html) type
 * composed of [vertices with attributes](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#vertexAttributes). The vertices include
 * geographic position, normals that affect lighting/shading and UV coordinates that
 * can be used to map images to the mesh. Vertices are combined into 3D primitives
 * to render the mesh in the scene (only triangle primitives are currently supported).
 *
 * Mesh geometries can have an intrinsic material that determines how it is being
 * displayed. Similar to 3D objects in scene layers, mesh geometries are symbolized with a
 * [MeshSymbol3D](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-MeshSymbol3D.html) symbol containing a
 * [FillSymbol3DLayer](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-FillSymbol3DLayer.html).
 *
 * To support multiple materials (as is often the case for complex 3D models), meshes
 * may define [components](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#components) that define a material for a specific region
 * in the mesh. In addition to supporting multiple materials, components can also
 * reuse vertices that would otherwise be duplicated to form triangles.
 *
 * Meshes are loadable since 4.27. In particular when meshes come from remote services like
 * through [SceneLayer.queryFeatures()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-SceneLayer.html#queryFeatures), then
 * the contents of the mesh needs to be loaded asynchronously through the
 * [load()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#load) method before
 * [vertexAttributes](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#vertexAttributes),
 * [extent](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#extent),
 * [components](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#components), etc. are available.
 *
 * Meshes represent fully georeferenced 3D geometry and care needs to be taken when importing mesh data.
 * <details>
 * <summary>Read More</summary>
 *
 * It is typical for modern 3D GIS workflows that 3D geometry data be represented by 3D models, which can be stored in different file formats like glTF, OBJ, FBX, IFC, etc. These models can come from different sources, such as 3D modeling software like SketchUp or Blender, CAD software like Revit, or even custom mesh generation code.
 *
 * While some of the software may work in a georeferenced space and some of the file formats, such as IFC, may be georeferenced, much of the software and most of the model file formats are not georeferenced. This presents the challenge of expressing different georeferencing scenarios while maintaining a fast and efficient experience when displaying and editing 3D model content. In the Maps SDK we strive to strike a good balance between allowing our users to work with different scenarios while preventing situations in which good display and editing experience cannot be provided.
 *
 * <span id="mesh-api"></span>
 * ## Mesh API
 *
 * The entry point for representing 3D models in the Maps SDK is the [Mesh](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html). We refer to the API reference for details on mesh [components](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#components), [MeshComponent.material](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshComponent.html#material) and how to create meshes. This guide is concerned with georeferencing meshes.
 *
 * A mesh represents a georeferenced 3D model in the Maps SDK. In order to fully georeference meshes three things are needed:
 * 1. Spatial reference
 * 2. Location of the mesh in that spatial reference. We call this the origin.
 * 3. The coordinate system in which mesh vertices are provided. We call it the vertex space.
 *
 * Given these three things, meshes can be fully georeferenced. However, for certain configurations of spatial reference, mesh vertex space and viewing mode, costly projection may be required. Because that would greatly affect display and editing performance, we decided to not display or allow editing in those cases. Please see the [limitations](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#limitations) section for an overview of these restrictions.
 *
 * The [spatial reference](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-SpatialReference.html) of the mesh is provided with its construction. When using one of the create functions, such as
 * [createFromGLTF()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#createFromGLTF), the spatial reference will be taken from the provided location.
 *
 * ### Mesh vertex spaces
 *
 * The origin and spatial reference of a mesh provide georeferencing, but only for the origin. A mesh is composed of vertices, and they may exist in different coordinate systems depending on the data source. Hence, to fully georeference the mesh, it's crucial to define the coordinate system associated with the mesh vertices. The [mesh vertex space property](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#vertexSpace) was introduced to address this need. This property specifies the meaning of the mesh vertex coordinates, ensuring that the entire mesh can be correctly georeferenced.
 *
 * #### Mesh local vertex space
 *
 * Most popular 3D model formats, such as glTF, are not georeferenced and represent the mesh vertex coordinates in a plain **local cartesian** space with some length unit (e.g. `meters` for glTF). The coordinate (0,0,0) is the origin. We call this coordinate system "local" and represent it using the [MeshLocalVertexSpace](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshLocalVertexSpace.html). The units in this vertex space are always "meters".
 *
 * <img src="https://developers.arcgis.com/javascript/latest/assets/img/apiref/geometry/mesh-local-vertex-space.png" style="width:300px;"/>
 *
 * *local vertex space*
 *
 * Georeferencing local coordinates is done by "putting them on the map" using a georeferenced cartesian reference frame. This frame is found by using the [local tangent plane](https://en.wikipedia.org/wiki/Local_tangent_plane_coordinates) at the georeferenced origin of the mesh. When the spatial reference uses a geographic coordinate system (GCS) or Web Mercator, the tangent plane is aligned such that the local Y tangent vector is always pointing to the north pole resulting in the east, north, up (ENU) frame.
 *
 * Currently we use the tangent plane of the sphere even for ellipsoidal geographic coordinate systems. This is a simplification we use as we render on a perfect sphere in global viewing mode.
 *
 * <img src="https://developers.arcgis.com/javascript/latest/assets/img/apiref/geometry/mesh-local-vertex-space-on-GCS-or-WM.png" style="width:300px;"/>
 *
 * *local vertex space on GCS or Web Mercator (ENU)*
 *
 * A [local vertex space](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshLocalVertexSpace.html) with a spatial reference which is a GCS or Web Mercator is efficient to work with as the tangent plane is easy to find and we can simply move the vertices to its georeferenced location using efficient linear transformations. This comes at the cost of an approximation error between the tangent plane and the actual surface. Consequently for larger models, this error increases while it decreases as the models get smaller.
 *
 * There is an important element to consider when a mesh is created with a [local vertex space](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshLocalVertexSpace.html) (e.g. by creating it from a glTF) and displayed in local viewing mode where a projected coordinate system (PCS) is used:
 *
 * The projection introduces a warping and distortion of the space in order to allow mapping of surface coordinates to a plane. This produces a mismatch between the linear coordinates of the local vertex space and the warped, non-linear coordinates of the underlying spatial reference. While steps along a line in the local vertex space are of same length, steps along a line in the underlying spatial reference are not. This means that measuring the same line in local space and the underlying spatial reference will produce different measurements. This difference further depends on the origin location of the mesh. It is important to realize that this scenario cannot be used when correct georeferencing is required.
 *
 * #### Mesh georeferenced vertex spaces
 *
 * The [georeferenced vertex space](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshGeoreferencedVertexSpace.html) indicates that mesh vertices are already projected and that their coordinates are in the spatial reference of the mesh. If an [MeshGeoreferencedVertexSpace.origin](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshGeoreferencedVertexSpace.html#origin) is provided, those vertex coordinates are interpreted as offsets relative to the origin. Otherwise, the coordinates are interpreted as absolute.
 *
 * <img src="https://developers.arcgis.com/javascript/latest/assets/img/apiref/geometry/mesh-georeferenced-vertex-space-on-PCS.png" style="width:300px;"/>
 *
 * *georeferenced vertex space on PCS*
 *
 * Display and editing are efficient for meshes with a georeferenced vertex space and when the spatial reference is a projected coordinate system and matches the spatial reference of the view. This is because in those cases, manipulations like moving a mesh can be expressed as linear transformations.
 *
 * ## The effect of viewing modes
 *
 * We will not display or allow edits for configurations where efficient display or editing is not possible due to costly reprojections being required. It is important to realize that the [SceneView.viewingMode](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-SceneView.html#viewingMode) defines the spatial reference in which the data is displayed and hence has a direct effect on which vertex space and spatial reference combination of meshes can be done efficiently. This means that, depending on the viewing mode, display and editing of meshes with certain combinations of vertex space and spatial reference are not supported. See [limitations](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#limitations) for an overview.
 *
 * We established that for mesh spatial references which use a geographic coordinate system (or Web Mercator) and a local vertex space, display and editing can be done efficiently. That is true for `"global"` viewing mode, where the view uses a geographic coordinate system (or Web Mercator) for display.
 *
 * Meshes with a georeferenced vertex space and a spatial reference using a projected coordinate system (PCS) can be displayed and edited efficiently in a view using the `"local"` viewing mode and when the view has the same spatial reference as the mesh.
 *
 * ## Web Mercator
 *
 * Web Mercator is a spatial reference with a projected coordinate system and the de facto standard for web mapping applications. This is due to its suitability for efficient map tiling. Even though it uses a projected coordinate system, we still support using Web Mercator in global viewing mode. This is because of its importance for web mapping and also because projecting Web Mercator on the globe cancels out the strong distortions near the poles. It is the only PCS based spatial reference we support in global viewing mode.
 *
 * Web Mercator support for global viewing mode naturally extends to supporting efficient display and editing for meshes with a Web Mercator spatial reference and a local vertex space, even though it is based on a projected coordinate system. Since Web Mercator is a spatial reference based on a PCS, we also support efficient display and editing for Web Mercator with meshes using a georeferenced vertex space. Web Mercator is the only exception to the rule of only meshes with a spatial reference with a geographic coordinate system can be supported in global viewing mode.
 *
 * <span id="limitations"></span>
 * ## Limitations
 *
 * - See [Scene Layers](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-SceneLayer.html) in regards to limitations on display and editing for mesh features.
 *
 * ## Troubleshooting mesh georeferencing
 *
 * If meshes are not being displayed, then chances are that this is due to a configuration which the API does not support for display and editing.
 *
 * - First check the [SceneView.viewingMode](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-SceneView.html#viewingMode), [spatial reference](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#spatialReference) and [vertex space](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#vertexSpace) of the problematic mesh and consult the console of the JavaScript debugger. If the API rejects display of meshes, a warning message is printed.
 * - If it is determined that an unsupported configuration is used, consider switching the [SceneView.viewingMode](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-SceneView.html#viewingMode) in your application.
 * - If there is no other option, consider changing the data by switching to a supported spatial reference for the required [SceneView.viewingMode](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-SceneView.html#viewingMode) or by converting the mesh vertex data between local and georeferenced vertex space.
 * - If meshes are displayed wrongly, then this could also be due to the vertex space not being correct. If applications export geometry with georeferenced coordinates as OBJ file for example, then one would need to use the `"georeferenced"` vertex space.
 *
 * </details>
 *
 * ## Create simple mesh geometry primitives
 *
 * The mesh geometry class has a number of convenience functions to create simple
 * primitive shapes. These shapes can help you get started with understanding
 * mesh geometries.
 *
 * ```js
 * // Create a box mesh geometry
 * let mesh = Mesh.createBox(location, {
 *   size: {
 *     width: 100,
 *     height: 50,
 *     depth: 50
 *   },
 *   material: {
 *     color: "red"
 *   }
 * });
 *
 * // Create a graphic and add it to the view
 * let graphic = new Graphic({
 *   geometry: mesh,
 *   symbol: {
 *     type: "mesh-3d",
 *     symbolLayers: [ { type: "fill" } ]
 *   }
 * });
 *
 * view.graphics.add(graphic);
 * ```
 *
 * ## Create mesh geometries manually
 *
 * Mesh geometries can be manually created by specifying [vertexAttributes](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#vertexAttributes) and
 * [components](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#components) like in the following example:
 *
 * ```js
 * // Create a mesh geometry representing a pyramid
 * let pyramidMesh = new Mesh({
 *   vertexAttributes: {
 *     // vertex positions for the Louvre pyramid, Paris
 *     position: [
 *       // vertex 0 - base of the pyramid, south
 *       2.336006, 48.860818, 0,
 *
 *       // vertex 1 - base of the pyramid, east
 *       2.336172, 48.861114, 0,
 *
 *       // vertex 2 - base of the pyramid, north
 *       2.335724, 48.861229, 0,
 *
 *       // vertex 3 - base of the pyramid, west
 *       2.335563, 48.860922, 0,
 *
 *       // vertex 4 - top of the pyramid
 *       2.335896, 48.861024, 21
 *     ]
 *   },
 *   // Add a single component with faces that index the vertices
 *   // so we only need to define them once
 *   components: [
 *     {
 *       faces: [
 *         0, 4, 3,
 *         0, 1, 4,
 *         1, 2, 4,
 *         2, 3, 4
 *       ]
 *     }
 *   ],
 *   // specify a spatial reference if the position of the vertices is not in WGS84
 * });
 *
 * // add the mesh geometry to a graphic
 * let graphic = new Graphic({
 *   geometry: pyramidMesh,
 *   symbol: {
 *     type: "mesh-3d",
 *     symbolLayers: [ { type: "fill" } ]
 *   }
 * });
 *
 * view.graphics.add(graphic);
 * ```
 *
 * **Note:** Starting with version 4.11 autocasting is no longer supported for Mesh geometry.
 *
 * @since 4.7
 * @see [MeshComponent](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshComponent.html)
 * @see [meshUtils](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-meshUtils.html)
 * @see [Sample - Working with 3d mesh primitives](https://developers.arcgis.com/javascript/latest/sample-code/geometry-mesh-primitives/)
 * @see [Sample - Low poly terrain using mesh geometry](https://developers.arcgis.com/javascript/latest/sample-code/geometry-mesh-elevation/)
 */
export default class Mesh extends MeshSuperclass {
  /**
   * Creates a mesh representing a box. The spatial reference of the resulting mesh is the same
   * as the location where it is placed.
   *
   * #### Box UV coordinate space
   *
   * The box geometry will have UV coordinates generated according to the following scheme:
   *
   * <img src="https://developers.arcgis.com/javascript/latest/assets/img/apiref/geometry/mesh-box-uv.png" width="300" height="300"/>
   *
   * @param location - The location bottom center of the box.
   * @param parameters - Parameters to configure the box creation.
   * @returns The resulting mesh.
   * @example
   * let mesh = Mesh.createBox(point, {
   *   size: {
   *     width: 10,
   *     height: 100,
   *     depth: 20
   *   },
   *   material: {
   *     color: "green"
   *   }
   * });
   * @example
   * let mesh = Mesh.createBox(point, {
   *   imageFace: "top",
   *   material: {
   *     colorTexture: new MeshTexture({ url: "./url-to-image.png" })
   *   }
   * });
   */
  static createBox(location: Point, parameters?: CreateBoxParameters): Mesh;
  /**
   * Creates a mesh representing a cylinder. The spatial reference of the resulting mesh is the same
   * as the location where it is placed.
   *
   * #### Cylinder UV coordinate space
   *
   * The cylinder geometry will have UV coordinates generated according to the following scheme
   * (example is shown for 8 vertices cylinder):
   *
   * <img src="https://developers.arcgis.com/javascript/latest/assets/img/apiref/geometry/mesh-cylinder-uv.png" width="300" height="300"/>
   *
   * @param location - The location of the bottom center of the cylinder.
   * @param parameters - Parameters to configure the cylinder creation.
   * @returns The resulting mesh.
   */
  static createCylinder(location: Point, parameters?: CreateCylinderParameters): Mesh;
  /**
   * Creates a new mesh geometry from a glTF model referenced by the `url` parameter.
   *
   * The spatial reference of the resulting mesh is the same as the spatial reference of the `location` parameter. For
   * more information on the supported glTF features you can read the
   * [Visualizing points with 3D symbols](https://developers.arcgis.com/javascript/latest/visualizing-points-3d/) guide topic. Animations are currently unsupported.
   *
   * @param location - The location of the origin of the model. If the location does not
   *  contain a z-value, z is assumed to be `0`.
   * @param url - The URL of the glTF model. The URL should point to a glTF file (.gltf or .glb) which can
   *  reference additional binary (.bin) and image files (.jpg, .png).
   * @param parameters - Parameters to configure the mesh from glTF creation.
   * @returns A promise that resolves to a mesh geometry representing the loaded
   *  glTF model.
   * @since 4.11
   */
  static createFromGLTF(location: Point, url: string, parameters?: CreateFromGLTFParameters): Promise<Mesh>;
  /**
   * Creates a new mesh geometry from a polygon geometry. The resulting mesh contains only
   * a position vertex attribute and a single component with faces. The default shading will be
   * set to `flat`. The spatial reference of the resulting mesh is the same
   * as the input polygon. The resulting mesh will not contain any UV nor normal vertex attributes.
   *
   * @param polygon - The input polygon.
   * @param parameters - Optional parameters.
   * @returns A new mesh representing the triangulated polygon.
   */
  static createFromPolygon(polygon: Polygon, parameters?: CreateFromPolygonParameters): Mesh;
  /**
   * Creates a mesh representing a plane. The spatial reference of the resulting mesh is the same
   * as the location where it is placed. A plane consists of two triangles and may be conveniently
   * oriented at creation time.
   *
   * #### Plane UV coordinate space
   *
   * The plane geometry will have UV coordinates generated according to the following scheme:
   *
   * <img src="https://developers.arcgis.com/javascript/latest/assets/img/apiref/geometry/mesh-plane-uv.png" width="300" height="300"/>
   *
   * @param location - The location of the bottom center of the plane.
   * @param parameters - Parameters to configure the plane creation.
   * @returns The resulting mesh.
   */
  static createPlane(location: Point, parameters?: CreatePlaneParameters): Mesh;
  /**
   * Creates a mesh representing a sphere. The spatial reference of the resulting mesh is the same
   * as the location where it is placed.
   *
   * #### Sphere UV coordinate space
   *
   * The sphere geometry will have UV coordinates generated according to the following scheme
   * (example is shown for 8x8 vertices sphere):
   *
   * <img src="https://developers.arcgis.com/javascript/latest/assets/img/apiref/geometry/mesh-sphere-uv.png" width="300" height="300"/>
   *
   * @param location - The location of the bottom center of the sphere.
   * @param parameters - Parameters to configure the sphere creation.
   * @returns The resulting mesh.
   */
  static createSphere(location: Point, parameters?: CreateSphereParameters): Mesh;
  constructor(properties?: MeshProperties);
  /**
   * An array of mesh components that can be used to apply materials
   * to different regions of the same mesh. There are three common
   * usage patterns for components.
   *
   * 1. **Specify a material for the whole mesh.** In this case, use a single
   *    component with only a material (leaving faces as `null`).
   * 2. **Reuse vertex attributes.** When modeling continuous surfaces,
   *    it can be convenient to only specify vertices once and then
   *    simply refer to them. In this case, use a single component
   *    with faces set to index the vertex attributes that form
   *    triangles.
   * 3. **Specify multiple materials for the same mesh.** In this case,
   *    use multiple components with faces that determine to which region
   *    of the mesh the material of the component applies.
   */
  get components(): MeshComponent[] | null | undefined;
  set components(value: MeshComponentProperties[] | null | undefined);
  /**
   * The 3D extent of the mesh geometry. The extent is computed from the
   * vertex positions stored in the [vertexAttributes](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#vertexAttributes).
   * The 3D extent is computed on-demand and cached. If you modify the
   * vertexAttributes manually, then you must call
   * [vertexAttributesChanged()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#vertexAttributesChanged) to make sure the
   * extent will be recomputed.
   */
  get extent(): Extent;
  /**
   * The origin of the mesh. This corresponds to the vertex space origin for relative vertex spaces.
   * For absolute vertex spaces, the origin is at the bottom of the mesh.
   *
   * @since 4.30
   */
  get origin(): Point;
  /**
   * Additional local transformation of the mesh vertices. The transform is ignored if the [vertexSpace)(#vertexSpace)
   * is of type [georeferenced](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshGeoreferencedVertexSpace.html) and does not specify
   * an [MeshGeoreferencedVertexSpace.origin](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshGeoreferencedVertexSpace.html#origin).
   */
  get transform(): MeshTransform | null | undefined;
  set transform(value: MeshTransformProperties | null | undefined);
  /** The string value representing the type of geometry. */
  get type(): "mesh";
  /**
   * Object describing the attributes of each vertex of the mesh. Vertex attributes
   * are flat numerical arrays that describe the position (mandatory), normal (used for
   * lighting calculations and shading) and UV (used for mapping material images to the
   * mesh surface) for each vertex.
   *
   * Vertex attributes can be addressed by indices specified in the components
   * [MeshComponent.faces](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshComponent.html#faces) property. If the
   * mesh does not contain any components, or if a component does not specify any faces,
   * then the vertex attributes are interpreted as if each consecutive vertex triple
   * makes up a triangle.
   *
   * @example
   * let mesh = new Mesh({ spatialReference: SpatialReference.WebMercator });
   *
   * // Specify vertices for two triangles that make up a square
   * // around a provided point. UV coordinates are set up to cover the square
   * // from (0, 0) to (1, 1) from corner to corner.
   * mesh.vertexAttributes = {
   *   position: [
   *     pt.x - 10, pt.y - 10, 100,
   *     pt.x + 10, pt.y - 10, 100,
   *     pt.x + 10, pt.y + 10, 100,
   *
   *     pt.x - 10, pt.y - 10, 100,
   *     pt.x + 10, pt.y + 10, 100,
   *     pt.x - 10, pt.y + 10, 100
   *   ],
   *   uv: [
   *     0, 0,
   *     1, 0,
   *     1, 1,
   *
   *     0, 0,
   *     1, 1,
   *     0, 1
   *   ]
   * };
   */
  get vertexAttributes(): MeshVertexAttributes;
  set vertexAttributes(value: MeshVertexAttributesProperties);
  /** The vertex space of the mesh. See [mesh API](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#mesh-api) for details. */
  get vertexSpace(): MeshVertexSpaceUnion;
  /**
   * Adds a component to the mesh.
   *
   * @param component - The component to add.
   */
  addComponent(component: MeshComponentProperties): void;
  /**
   * Centers the mesh at the specified location without changing its scale. This effectively adjusts the mesh
   * origin and mesh vertices such that vertices are given relative to the new location and the new location
   * is the new origin. The effective georeferenced vertex positions will not change.
   *
   * The mesh will be modified in place. To modify a copy of the mesh instead, use [clone()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#clone)
   * before calling [centerAt()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#centerAt).
   *
   * @param location - The location at which to center the mesh.
   * @param parameters - Additional parameters.
   * @returns The modified mesh.
   */
  centerAt(location: Point, parameters?: CenterAtParameters): this;
  /**
   * Creates a deep clone of the Mesh object.
   *
   * @returns A new instance of a Mesh object equal to the object used to call `.clone()`.
   */
  clone(): this;
  /**
   * Offsets the mesh geometry by the specified distance in x, y, and z. The units of x, y, and z are the
   * units of the spatial reference. When the vertex space is local or georeferenced with an origin,
   * the offset is applied to the origin of the vertex space. When the vertex space is georeferenced
   * without origin, the offset is applied to the vertex positions directly.
   *
   * The mesh will be modified in place. To modify a copy of the mesh instead, use [clone()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#clone)
   * before calling [offset()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#offset).
   *
   * @param dx - The amount to offset the geometry in the x direction.
   * @param dy - The amount to offset the geometry in the y direction.
   * @param dz - The amount to offset the geometry in the z direction.
   * @returns The modified mesh (this instance).
   */
  offset(dx: number, dy: number, dz: number): this;
  /**
   * Removes a component from the mesh.
   *
   * @param component - The component to remove.
   */
  removeComponent(component: MeshComponent): void;
  /**
   * Rotates the mesh geometry around its x, y and z axis (in that order). For each rotation angle,
   * the rotation direction is clockwise when looking in the direction of the respective axis.
   * The mesh will be modified in place. To modify a copy of the mesh instead, use [clone()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#clone)
   * before calling [rotate()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#rotate).
   *
   * @param angleX - The angle by which to rotate around the x-axis (in degrees).
   * @param angleY - The angle by which to rotate around the y-axis (in degrees).
   * @param angleZ - The angle by which to rotate around the z-axis (in degrees).
   * @param parameters - Additional parameters.
   * @returns The modified mesh (this instance).
   * @example
   * // rotate the mesh in the horizontal plane (around the z axis) by 90 degrees and tilt it in the lateral
   * // vertical plane (around the y axis) by 20 degrees.
   * mesh.rotate(0, 20, 90);
   */
  rotate(angleX: number, angleY: number, angleZ: number, parameters?: RotateParameters): this;
  /**
   * Scales the mesh geometry by the specified factor. The mesh will be modified in place.
   * To modify a copy of the mesh instead, use [clone()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#clone) before calling [scale()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html#scale).
   *
   * @param factor - The amount to scale the geometry.
   * @param parameters - Additional parameters.
   * @returns The modified mesh (this instance).
   */
  scale(factor: number, parameters?: ScaleParameters): this;
  /**
   * Export a mesh to a binary glTF (glb) representation. The resulting ArrayBuffer could be uploaded
   * to a service or give an application the option to download a representation of the mesh.
   *
   * @param options - Additional options.
   * @returns The binary glTF data.
   * @since 4.30
   * @example
   * function downloadBufferAsFile(filename, buffer, type) {
   *   const objectUrl = URL.createObjectURL(new Blob([buffer], { type }));
   *
   *   const a = document.createElement("a");
   *   a.download = filename;
   *   a.href = objectUrl;
   *   a.style.display = "none";
   *
   *   document.body.appendChild(a);
   *   a.click();
   *
   *   document.body.removeChild(a);
   *   URL.revokeObjectURL(objectUrl);
   * }
   *
   * const buffer = await mesh.toBinaryGLTF();
   * downloadBufferAsFile("model.glb", buffer, "model/gltf-binary");
   */
  toBinaryGLTF(options?: ExportGLTFOptions): Promise<ArrayBuffer>;
  /**
   * Notifies that any cached values that depend on vertex attributes need to be recalculated. Use this
   * method after modifying the vertex attributes in place so that values that depend on them (such as
   * the calculation of the extent) are recalculated accordingly.
   */
  vertexAttributesChanged(): void;
}
declare const MeshSuperclass: typeof BaseGeometry & typeof EsriPromiseMixin & typeof LoadableMixin & typeof ClonableMixin

export interface CreateFromPolygonParameters {
  /** The material to be used for the mesh. */
  material?: MeshMaterialProperties;
}