.. _filters.hag_nn:

filters.hag_nn
===============================================================================

The **Height Above Ground Nearest Neighbor filter** takes as input a point
cloud with ``Classification`` set to 2 for ground points.  It creates a new
dimension, ``HeightAboveGround``, that contains the normalized height values.

.. note::

   We expect ground returns to have the classification value of 2 in keeping
   with the `ASPRS Standard LIDAR Point Classes
   <http://www.asprs.org/a/society/committees/standards/LAS_1_4_r13.pdf>`_.

Ground points may be generated by :ref:`filters.pmf` or :ref:`filters.smrf`,
but you can use any method you choose, as long as the ground returns are
marked.

Normalized heights are a commonly used attribute of point cloud data. This can
also be referred to as *height above ground* (HAG) or *above ground level*
(AGL) heights. In the end, it is simply a measure of a point's relative height
as opposed to its raw elevation value.

The filter finds the `count`_ ground points nearest the non-ground point under
consideration.  It calculates an average ground height weighted by the distance
of each ground point from the non-ground point.  The ``HeightAboveGround`` is
the difference between the ``Z`` value of the non-ground point and the
interpolated ground height.

.. embed::

Example #1
----------

Using the autzen dataset (here shown colored by elevation), which already has
points classified as ground

.. image:: ./images/autzen-elevation.png
   :height: 400px

we execute the following pipeline

.. code-block:: json

  [
      "autzen.laz",
      {
          "type":"filters.hag_nn"
      },
      {
          "type":"writers.laz",
          "filename":"autzen_hag_nn.laz",
          "extra_dims":"HeightAboveGround=float32"
      }
  ]

which is equivalent to the ``pdal translate`` command

::

    $ pdal translate autzen.laz autzen_hag_nn.laz hag_nn \
        --writers.las.extra_dims="HeightAboveGround=float32"

In either case, the result, when colored by the normalized height instead of
elevation is

.. image:: ./images/autzen-hag-nn.png
   :height: 400px

Example #2
-------------------------------------------------------------------------------

In the previous example, we chose to write ``HeightAboveGround`` using the
``extra_dims`` option of :ref:`writers.las`. If you'd instead like to overwrite
your Z values, then follow the height filter with :ref:`filters.ferry` as shown

.. code-block:: json

  [
      "autzen.laz",
      {
          "type":"filters.hag_nn"
      },
      {
          "type":"filters.ferry",
          "dimensions":"HeightAboveGround=>Z"
      },
      "autzen-height-as-Z.laz"
  ]


Example #3
-------------------------------------------------------------------------------

If you don't yet have points classified as ground, start with :ref:`filters.pmf`
or :ref:`filters.smrf` to label ground returns, as shown

.. code-block:: json

  [
      "autzen.laz",
      {
          "type":"filters.smrf"
      },
      {
          "type":"filters.hag_nn"
      },
      {
          "type":"filters.ferry",
          "dimensions":"HeightAboveGround=>Z"
      },
      "autzen-height-as-Z-smrf.laz"
  ]

Options
-------------------------------------------------------------------------------

_`count`
    The number of ground neighbors to consider when determining the height
    above ground for a non-ground point.  [Default: 1]

max_distance
    Use only ground points within `max_distance` of non-ground point when
    performing neighbor interpolation.  [Default: None]

allow_extrapolation
    If false and a non-ground point lies outside of the bounding box of all
    ground points, its ``HeightAboveGround`` is set to 0.  If true,
    extrapolation is used to assign the ``HeightAboveGround`` value.  [Default:
    false]
