.. role:: ts-api-decorator

#############
GeometryModel
#############

.. js:module:: cee.geo
   :noindex:

.. container:: ts-api-section

   .. js:class:: GeometryModel

      The ``GeometryModel`` implements a client-side model that can handle a large number of parts efficiently.

      The model can be created and modified in the client application and is not dependent on a server (unlike 
      ug.RemoteModel). 

      Each view can contain many ``GeometryModels``. A ``GeometryModel`` is a collection of parts. Each ``Part`` is defined
      by its ``Mesh``, which describes the triangles, lines and points, and by its PartSettings, which specify how the part
      is rendered.
  
      A ``GeometryModel`` can have a transformation matrix (``transformationMatrix``) useful for scene composition
      or for doing rigid body animations.

      Picking is supported via ``rayIntersect`` which returns a ``HitItem`` containing the intersection point, part index
      and primitive index within that part, and ``regionIntersect`` which returns an array of parts (partially) within 
      a given rectangle in screen coordinates.

      See the example in Examples/BuildYourFirstApp/1-HelloEnvision for how to use the ``GeometryModel``.

      Here is a simple example that creates a geometry model with one part and one triangle and adds it to the current view:

      .. code-block:: javascript

         var geoModel = new cee.geo.GeometryModel();

         // Create a simple one triangle one part model
         var indices = [0, 1, 2];
         var triangleVertices = [0,0,0,  1,0,0,  0,1,0];

         let part = geoModel.addPart();
         let mesh = new cee.geo.MeshIndexedTriangles(triangleVertices, indices);
         part.mesh = mesh;

         part.settings.color = new cee.Color3(0, 1, 0);

         var view = myViewer.getViewAt(0);
         view.addModel(geoModel);
         view.requestRedraw();




.. container:: api-index-section

   .. rubric:: Constructors

   .. rst-class:: api-index-list-item api-kind-constructor api-parent-kind-class

   * :js:meth:`~cee.geo.GeometryModel.constructor`



.. container:: api-index-section

   .. rubric:: Accessors

   .. rst-class:: api-index-list-item api-kind-accessor api-parent-kind-class

   * :js:attr:`~cee.geo.GeometryModel.ignoreViewClipping`
   * :js:attr:`~cee.geo.GeometryModel.name`
   * :js:attr:`~cee.geo.GeometryModel.partCount`
   * :js:attr:`~cee.geo.GeometryModel.transformationMatrix`



.. container:: api-index-section

   .. rubric:: Methods

   .. rst-class:: api-index-list-item api-kind-method api-parent-kind-class

   * :js:meth:`~cee.geo.GeometryModel.addPart`
   * :js:meth:`~cee.geo.GeometryModel.deleteAllParts`
   * :js:meth:`~cee.geo.GeometryModel.deletePartAt`
   * :js:meth:`~cee.geo.GeometryModel.deletePartsAt`
   * :js:meth:`~cee.geo.GeometryModel.getBoundingBox`
   * :js:meth:`~cee.geo.GeometryModel.getDefaultCameraConfig`
   * :js:meth:`~cee.geo.GeometryModel.getPartArray`
   * :js:meth:`~cee.geo.GeometryModel.getPartAt`
   * :js:meth:`~cee.geo.GeometryModel.rayIntersect`
   * :js:meth:`~cee.geo.GeometryModel.regionIntersect`
   * :js:meth:`~cee.geo.GeometryModel.setColorPerPartFromMapper`





------------

Constructors
============

.. container:: ts-api-section

   .. js:function:: GeometryModel.constructor()



      Constructor


      :rtype: GeometryModel



Accessors
=========

.. container:: ts-api-section

   .. js:function:: GeometryModel.ignoreViewClipping()



      Enable or disable option to ignore view clipping in this model


      :rtype: boolean

   .. js:function:: GeometryModel.ignoreViewClipping( ignore)

      :param ignore: None
      :type ignore: boolean


      :rtype: void



.. container:: ts-api-section

   .. js:function:: GeometryModel.name()



      The name of the geometry model. Mainly used for debugging.


      :rtype: string

   .. js:function:: GeometryModel.name( name)

      :param name: None
      :type name: string


      :rtype: void



.. container:: ts-api-section

   .. js:function:: GeometryModel.partCount()



      The number of parts in the model.


      :rtype: number



.. container:: ts-api-section

   .. js:function:: GeometryModel.transformationMatrix()



      The transformation matrix to use for this model.

      If specified, all parts in the model will be transformed by this matrix. This can be useful for scene
      composition and for rigid body type animations. The default is null.


      :rtype: Mat4

   .. js:function:: GeometryModel.transformationMatrix( transformationMatrix)

      :param transformationMatrix: None
      :type transformationMatrix: Mat4


      :rtype: void



Methods
=======

.. rst-class:: ts-api-section

addPart
-------

.. js:method:: GeometryModel.addPart()



   Creates a new part and adds it to the model.

   Returns the newly created part.


   :rtype: Part

.. rst-class:: ts-api-section

deleteAllParts
--------------

.. js:method:: GeometryModel.deleteAllParts()



   Deletes all parts in model


   :rtype: void

.. rst-class:: ts-api-section

deletePartAt
------------

.. js:method:: GeometryModel.deletePartAt( partIndex)

   :param partIndex: None
   :type partIndex: number


   Deletes the part at the given (zero based) index.


   :rtype: void

.. rst-class:: ts-api-section

deletePartsAt
-------------

.. js:method:: GeometryModel.deletePartsAt( partIndicesArr)

   :param partIndicesArr: None
   :type partIndicesArr: [number]


   Deletes the parts at the given indices.


   :rtype: void

.. rst-class:: ts-api-section

getBoundingBox
--------------

.. js:method:: GeometryModel.getBoundingBox([ options])

   :param options: :ts-api-decorator:`optional` None
   :type options: ModelBoundingBoxOptions


   Returns the ``BoundingBox`` (in world coordinates) of the model.

   By default, the returned bounding box will only include visible parts. 
   If you want the bounding box to include all parts, regardless of visibility, set 
   the ``ModelBoundingBoxOptions.includeHiddenParts`` option to true. 
   Please note that there might be a significant performance penalty for including hidden parts.


   :rtype: BoundingBox

.. rst-class:: ts-api-section

getDefaultCameraConfig
----------------------

.. js:method:: GeometryModel.getDefaultCameraConfig()



   Returns default camera configuration, which is always null for this model.


   :rtype: unknown

.. rst-class:: ts-api-section

getPartArray
------------

.. js:method:: GeometryModel.getPartArray()



   Returns a read only array with all parts


   :rtype: unknown

.. rst-class:: ts-api-section

getPartAt
---------

.. js:method:: GeometryModel.getPartAt( partIndex)

   :param partIndex: None
   :type partIndex: number


   Returns an active reference to the part at the given (zero based) index.


   :rtype: Part

.. rst-class:: ts-api-section

rayIntersect
------------

.. js:method:: GeometryModel.rayIntersect( ray)

   :param ray: None
   :type ray: Ray


   Performs picking on the model.

   If something was hit, returns a HitItem containing information about the part and primitive that was hit.

   If nothing was hit, returns null.


   :rtype: HitItem

.. rst-class:: ts-api-section

regionIntersect
---------------

.. js:method:: GeometryModel.regionIntersect( x, y, width, height, view, acceptPartiallyContainedParts)

   :param x: None
   :type x: number
   :param y: None
   :type y: number
   :param width: None
   :type width: number
   :param height: None
   :type height: number
   :param view: None
   :type view: View
   :param acceptPartiallyContainedParts: None
   :type acceptPartiallyContainedParts: boolean


   Returns the parts that are (partially) inside the given region.

   The returned list of parts will contain all parts that are inside the given region. If acceptPartiallyContainedParts
   is set to true, parts will be considered inside if they are partially (at least one of the vertices) inside 
   the region. If false, the entire part needs to be completely inside the region. 

   Please note that this method works at the vertex level. This means that for a part to be considered 
   partially inside the region, at least one of its vertices must be within the specified region. 
   If acceptPartiallyContainedParts is set to false, all vertices must be inside the region. 
   If this method is used in combination with view clipping planes, only vertices that are visible with 
   regards to the specified clipping planes will be considered.

   The x and y coordinates must be specified in OpenGL style coordinates, which means a right handed coordinate system 
   with the origin in the lower left corner of the window. The HTML coordinate system is with origin in top left, 
   so if this is your input (e.g. MouseEvent.offsetY, clientY, pageY, etc.) you will have to flip the Y coordinate. 
   The x and y are specified in native pixels, so you will have to adjust the input for the current devicePixelRatio 
   (window.devicePixelRatio).

   The width and height are specified in native pixels. So you will have to adjust the input for the current devicePixelRatio 
   (window.devicePixelRatio).

   NOTE: This is the only method using OpenGL/WebGL style coordinates. All other relevant methods use 
   Canvas/Viewer local CSS coordinates. This behavior will change in an upcoming major release.

   **Example:** Change the color of all parts within the rectangle defined by a rubber band


   .. code-block:: javascript


      // this.m_startX/this.m_startY is the event.offsetX/event.offsetY at the 
      // start of the region definition
      endRegionSelection(event: MouseEvent) {
          this.m_regionSelectActive = false;

          let pixelScaleFactor = window.devicePixelRatio || 1;
          let startXPixels = this.m_startX * pixelScaleFactor;
          let startYPixels = this.m_startY * pixelScaleFactor;
          let endXPixels = event.offsetX * pixelScaleFactor;
          let endYPixels = event.offsetY * pixelScaleFactor;

          // Note: Canvas height is in native pixels, so no scaling with pixelScaleFactor
          let canvasHeightPixels = this.m_canvas.height;      

          let leftPixels = Math.min(startXPixels, endXPixels); 
          let rightPixels = Math.max(startXPixels, endXPixels); 
          let topPixels = Math.max(canvasHeightPixels - startYPixels, 
                                   canvasHeightPixels - endYPixels); 
          let bottomPixels = Math.min(canvasHeightPixels - startYPixels, 
                                   canvasHeightPixels - endYPixels); 
          let widthPixels = (rightPixels - leftPixels);
          let heightPixels = (topPixels - bottomPixels);

          let parts = this.m_model.regionIntersect(leftPixels, bottomPixels, 
                                        widthPixels, heightPixels, this.m_view, true);

          let selectColor = new cee.Color3(1,0,1);
          for(let part of parts) {
              part.settings.color = selectColor;
          }

          this.m_regionSelectionDiv.hidden = true;
      }    



   :rtype: [Part]

.. rst-class:: ts-api-section

setColorPerPartFromMapper
-------------------------

.. js:method:: GeometryModel.setColorPerPartFromMapper( scalarMapper, perPartResult)

   :param scalarMapper: None
   :type scalarMapper: ScalarMapper
   :param perPartResult: None
   :type perPartResult: ArrayLike <number>


   Sets the color of the parts in the model based on the given scalarMapper and a scalar per part.

   This is useful for showing per-part scalar results on a GeometryModel.

   To show a color legend representing the scalar mapper in a View, use the 
   View.overlay.addCustomColorLegendForScalarMapper() method.

   This method is just a helper for doing the following:

   .. code-block:: javascript

      const partCount = this.partCount;
      for (let i = 0; i < partCount; ++i) {
          let color = scalarMapper.mapToColor(perPartResult[i]);
          let part = this.getPartAt(i);
          part.settings.color = color.toColor3();
          part.settings.opacity = color.a;
      }



   :rtype: void

