{*
 *******************************************************************************
 *
 *  Copyright 2026 RIEGL Laser Measurement Systems
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  SPDX-License-Identifier: Apache-2.0
 *
 *******************************************************************************
 *}
{*!
 *******************************************************************************
 *
 * \file    riegl.rdb.pointcloud.createSettings.pas
 * \author  RIEGL LMS GmbH, Austria
 * \brief   Database create settings (Pascal wrapper code)
 * \version 2015-10-14/AW: Initial version
 * \version 2016-07-13/AW: Documentation of 'chunkSizeLOD' updated
 * \version 2016-09-22/AW: Parameter 'cacheSize' changed from 32 to 64 bit type
 * \version 2016-12-20/AW: New functions to load/save settings from/to JSON
 * \version 2017-03-28/AW: Documentation of JSON load/save functions updated
 * \version 2019-01-15/AW: Parameter 'chunkMode' added
 * \version 2019-01-19/AW: Parameter 'lodMode' added
 * \version 2019-02-15/AW: Fix Pascal API wrapper of CreateSettings class
 * \version 2019-10-30/AW: Parameter 'optimizePointID' added (#3458)
 * \version 2024-11-26/AW: Parameter 'pointInsertMode' added (#5339)
 *
 *******************************************************************************
 *}

unit riegl.rdb.pointcloud.createSettings;

{******************************************************************************}
{***} INTERFACE {**************************************************************}
{******************************************************************************}

//---< INCLUDES >---------------------------------------------------------------

uses
  riegl.rdb,
  riegl.rdb.context,
  riegl.rdb.pointcloud.pointAttribute;

//---< RDB LIBRARY IMPORTS >----------------------------------------------------

//______________________________________________________________________________
{*!
 * \brief Default constructor
 *
 * All values are set to default values.
 *}
function rdb_pointcloud_create_settings_new(
  Context      : TRDBContextHandle;                 //!< [in] library context
  var Settings : TRDBPointcloudCreateSettingsHandle //!< [out] handle of created object
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Destroy settings object
 *}
function rdb_pointcloud_create_settings_delete(
  Context      : TRDBContextHandle;                 //!< [in] library context
  var Settings : TRDBPointcloudCreateSettingsHandle //!< [in] handle of object to delete
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
(*!
 * \brief Load settings from JSON string
 *
 * This function parses the given JSON string and applies all available
 * properties - missing properties are silently ignored (i.e. the value
 * remains unchanged). When parsing the JSON string fails, an exception
 * is thrown.
 *
 * Example JSON string:
 *
 *     {
 *         "primary_attribute": {
 *             "name": "riegl.xyz",
 *             "title": "XYZ",
 *             "description": "Cartesian point coordinates wrt. application coordinate system (0: X, 1: Y, 2: Z)",
 *             "unit_symbol": "m",
 *             "length": 3,
 *             "resolution": 0.00025,
 *             "minimum_value": -535000.0,
 *             "maximum_value": 535000.0,
 *             "default_value": 0.0,
 *             "storage_class": "variable",
 *             "compression_options": "shuffle",
 *             "scale_factor": 1.0
 *         },
 *         "chunk_mode": "point_count",
 *         "chunk_size": 65536,
 *         "lod_mode": "thinout",
 *         "chunk_size_lod": 20,
 *         "cache_size": 524288000,
 *         "compression_level": 10,
 *         "optimize_point_id": false,
 *         "point_insert_mode": "single-pass"
 *     }
 *)
function rdb_pointcloud_create_settings_json_load(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] attribute handle
  JSON     : TRDBString                          //!< [in] JSON string
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Save settings to JSON string
 * \see rdb_pointcloud_create_settings_json_load()
 *}
function rdb_pointcloud_create_settings_json_save(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] attribute handle
  var JSON : TRDBString                          //!< [out] JSON string
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Get primary point attribute
 *
 * The primary point attribute defines the attribute that is used
 * to sort and index the points. Usually the 3D point coordinates are
 * used for that. The primary attribute is automatically added to the
 * point cloud (using Pointcloud::attributeAdd()) and cannot be deleted.
 *
 * \see riegl::rdb::pointcloud::PointAttributes
 *}
function rdb_pointcloud_create_settings_get_primary_attribute(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  Value    : TRDBPointcloudPointAttributeHandle  //!< [out] current attribute
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Set primary point attribute
 * \see rdb_pointcloud_create_settings_get_primary_attribute()
 *}
function rdb_pointcloud_create_settings_set_primary_attribute(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  Value    : TRDBPointcloudPointAttributeHandle  //!< [in] new attribute
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Get point chunk mode
 *
 * Points are internally organized in chunks (primary point attribute index
 * tree leaves). The size of a chunk (in the dimension of the primary point
 * attribute) may either be fixed (predefined) or adapted automatically so
 * that the number of points in a chunk does not exceed a certain limit. In
 * both cases, the "size" is defined by parameter CreateSettings::chunkSize
 * and parameter CreateSettings::chunkMode defines the meaning of the value.
 *
 * POINT_COUNT = 1
 *   the chunk size defines the maximum number of points per chunk
 *   (the default mode)
 *
 * EDGE_LENGTH = 2
 *   the chunk size defines the edge length of a chunk as 2^N times
 *   resolution of the primary point attribute
 *}
function rdb_pointcloud_create_settings_get_chunk_mode(
  Context   : TRDBContextHandle;                  //!< [in] library context
  Settings  : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  var Value : TRDBUInt32                          //!< [out] current value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Set point chunk mode
 * \see rdb_pointcloud_create_settings_get_chunk_mode()
 *}
function rdb_pointcloud_create_settings_set_chunk_mode(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  Value    : TRDBUInt32                          //!< [in] new value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Get point chunk size
 * \see rdb_pointcloud_create_settings_get_chunk_mode()
 *}
function rdb_pointcloud_create_settings_get_chunk_size(
  Context   : TRDBContextHandle;                  //!< [in] library context
  Settings  : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  var Value : TRDBUInt32                          //!< [out] current value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Set point chunk size
 * \see rdb_pointcloud_create_settings_get_chunk_mode()
 *}
function rdb_pointcloud_create_settings_set_chunk_size(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  Value    : TRDBUInt32                          //!< [in] new value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Get level of detail mode
 *
 * A tree structure is used to sort and organize the point cloud. To create
 * a coarse representation of the point cloud (level of detail = "LOD"), a
 * number of equally distributed points is extracted from the tree leaf
 * nodes and copied to the parent nodes.
 *
 * The parameter CreateSettings::chunkSizeLOD defines how many points to
 * extract for LOD whereas the meaning of the value and the LOD creation
 * algorithm are defined by the parameter CreateSettings::lodMode.
 *
 * THINOUT = 1
 *   the LOD size defines the number of points to copy as a fraction of
 *   the total (original) number of points. So if the original point count
 *   is for example 19820526 and the size is set to 20%, then the number
 *   of LOD points to add is 3964106 (rounded) and the final total number
 *   of points is 23784632 (actual value may differ a little bit).
 *
 * COMBINE = 2
 *   the LOD size defines the number of binary subdivisions of the LOD
 *   node's volume in each dimension. So if the primary point attribute
 *   for example has a length of 2 (2D data) and the LOD size is set to 8,
 *   then each LOD node is divided into 2^8 * 2^8 = 2^(8*2) = 2^16 = 65536
 *   sub-volumes. All points of the node's immediate sub-nodes that fall
 *   into one of the sub-volumes are merged to a single point and stored
 *   in the LOD node. The method to merge the attribute values of a group
 *   of points can be defined for each point attribute separately (details
 *   see class PointAttribute).
 *}
function rdb_pointcloud_create_settings_get_lod_mode(
  Context   : TRDBContextHandle;                  //!< [in] library context
  Settings  : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  var Value : TRDBUInt32                          //!< [out] current value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Set level of detail mode
 * \see rdb_pointcloud_create_settings_get_lod_mode()
 *}
function rdb_pointcloud_create_settings_set_lod_mode(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  Value    : TRDBUInt32                          //!< [in] new value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Get level of detail size
 * \see rdb_pointcloud_create_settings_get_lod_mode()
 *}
function rdb_pointcloud_create_settings_get_chunk_size_lod(
  Context   : TRDBContextHandle;                  //!< [in] library context
  Settings  : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  var Value : TRDBUInt32                          //!< [out] current value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Set level of detail size
 * \see rdb_pointcloud_create_settings_get_lod_mode()
 *}
function rdb_pointcloud_create_settings_set_chunk_size_lod(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  Value    : TRDBUInt32                          //!< [in] new value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Get point cache size
 *
 * The database engine may buffer read and write operations in an
 * internal cache. This value defines the cache size in bytes (octets).
 *
 * Default: 500 MB
 *}
function rdb_pointcloud_create_settings_get_cache_size(
  Context   : TRDBContextHandle;                  //!< [in] library context
  Settings  : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  var Value : TRDBUInt32                          //!< [out] current value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;
//
function rdb_pointcloud_create_settings_get_cache_size_64(
  Context   : TRDBContextHandle;                  //!< [in] library context
  Settings  : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  var Value : TRDBUInt64                          //!< [out] current value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Set point cache size
 * \see rdb_pointcloud_create_settings_get_cache_size()
 *}
function rdb_pointcloud_create_settings_set_cache_size(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  Value    : TRDBUInt32                          //!< [in] new value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;
//
function rdb_pointcloud_create_settings_set_cache_size_64(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  Value    : TRDBUInt64                          //!< [in] new value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Get data compression level
 *
 * The database automatically compresses point data before it is
 * stored. The compression level defines the compression quality,
 * i.e. higher values produce smaller files.
 *
 * Range: 0..100 (i.e. percent)
 * Default: 10%
 *}
function rdb_pointcloud_create_settings_get_compression_level(
  Context   : TRDBContextHandle;                  //!< [in] library context
  Settings  : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  var Value : TRDBUInt8                           //!< [out] current value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Set data compression level
 * \see rdb_pointcloud_create_settings_get_compression_level()
 *}
function rdb_pointcloud_create_settings_set_compression_level(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  Value    : TRDBUInt8                           //!< [in] new value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Get point ID optimization
 *
 * Enable this option to apply optimizations to the point ID
 * attribute (riegl.id) that can result in smaller files.
 *
 * Default: False
 *
 * \note No optimizations are applied when:
 *       - points were inserted in a previous transaction
 *       - buffers for the point ID (riegl.id) or dynamic point attributes
 *         (e.g. "riegl.selected", "riegl.visible") are passed to the insert
 *         query (QueryInsert class)
 *
 * \warning When optimizations are enabled, the point ID no longer
 *          reflects the order in which the points were inserted.
 *}
function rdb_pointcloud_create_settings_get_optimize_point_id(
  Context   : TRDBContextHandle;                  //!< [in] library context
  Settings  : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  var Value : TRDBUInt32                          //!< [out] current value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Set point ID optimization
 * \see rdb_pointcloud_create_settings_get_optimize_point_id()
 *}
function rdb_pointcloud_create_settings_set_optimize_point_id(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  Value    : TRDBUInt32                          //!< [in] new value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Get point insert mode
 *
 * This setting specifies how points are to be inserted into the database.
 *
 * Supported values:
 *   - "single-pass" (default)
 *          Points are sorted and inserted into the internal index structure
 *          each time QueryInsert::next() is called. This is suitable for
 *          scenarios where the same objects are only scanned once or just
 *          a few times (e.g in TLS or MLS).
 *
 *   - "multi-pass"
 *          Points are sorted and inserted into the internal index structure
 *          after the last call to QueryInsert::next() when the transaction is
 *          committed. This is suitable for scenarios where the same objects are
 *          scanned multiple times (e.g. in ALS or ULS when the system passes
 *          over the same area several times without toggling data acquisition).
 *          This mode is only supported for 3D point clouds (e.g. when the
 *          primary point attribute is "riegl.xyz") and when no points have
 *          been inserted before. Otherwise "single-pass" mode is used instead.
 *          This mode implies "optimizePointID" and point IDs are not returned
 *          by the insert query.
 *
 * \note It is recommended to only check whether the string starts with one of
 *       the above values and to ignore all subsequent characters (mode-specific
 *       parameters may be added after the mode name in the future).
 *}
function rdb_pointcloud_create_settings_get_point_insert_mode(
  Context   : TRDBContextHandle;                  //!< [in] library context
  Settings  : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  var Value : TRDBString                          //!< [out] current value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//______________________________________________________________________________
{*!
 * \brief Set point insert mode
 * \see rdb_pointcloud_create_settings_get_point_insert_mode()
 *}
function rdb_pointcloud_create_settings_set_point_insert_mode(
  Context  : TRDBContextHandle;                  //!< [in] library context
  Settings : TRDBPointcloudCreateSettingsHandle; //!< [in] handle of object
  Value    : TRDBString                          //!< [in] new value
) : TRDBResult; cdecl; external riegl.rdb.RDB_LIBRARY_FILENAME;

//---< ENUM TRDBPointcloudChunkMode >-------------------------------------------
{*!
 * \brief Point chunk mode
 *
 * Points are internally organized in chunks (primary point attribute index
 * tree leaves). The size of a chunk (in the dimension of the primary point
 * attribute) may either be fixed (predefined) or adapted automatically so
 * that the number of points in a chunk does not exceed a certain limit. In
 * both cases, the "size" is defined by parameter CreateSettings::chunkSize
 * and parameter CreateSettings::chunkMode defines the meaning of the value.
 *}
type
  TRDBPointcloudChunkMode = (
    {*!
     * the chunk size defines the maximum number of points per chunk
     * (the default mode)
     *}
    RDB_CHUNK_MODE_POINT_COUNT = 1,

    {*!
     * the chunk size defines the edge length of a chunk as 2^N times
     * resolution of the primary point attribute
     *}
    RDB_CHUNK_MODE_EDGE_LENGTH = 2
  );

//---< ENUM TRDBPointcloudLodMode >---------------------------------------------
{*!
 * \brief Level of detail mode
 *
 * A tree structure is used to sort and organize the point cloud. To create
 * a coarse representation of the point cloud (level of detail = "LOD"), a
 * number of equally distributed points is extracted from the tree leaf
 * nodes and copied to the parent nodes.
 *
 * The parameter CreateSettings::chunkSizeLOD defines how many points to
 * extract for LOD whereas the meaning of the value and the LOD creation
 * algorithm are defined by the parameter CreateSettings::lodMode.
 *}
type
  TRDBPointcloudLodMode = (
    {*!
     * the LOD size defines the number of points to copy as a fraction of
     * the total (original) number of points. So if the original point count
     * is for example 19820526 and the size is set to 20%, then the number
     * of LOD points to add is 3964106 (rounded) and the final total number
     * of points is 23784632 (actual value may differ a little bit).
     *}
    RDB_LOD_MODE_THINOUT = 1,

    {*!
     * the LOD size defines the number of binary subdivisions of the LOD
     * node's volume in each dimension. So if the primary point attribute
     * for example has a length of 2 (2D data) and the LOD size is set to 8,
     * then each LOD node is divided into 2^8 * 2^8 = 2^(8*2) = 2^16 = 65536
     * sub-volumes. All points of the node's immediate sub-nodes that fall
     * into one of the sub-volumes are merged to a single point and stored
     * in the LOD node. The method to merge the attribute values of a group
     * of points can be defined for each point attribute separately (details
     * see class PointAttribute).
     *}
    RDB_LOD_MODE_COMBINE = 2
  );

//---< CLASS TRDBPointcloudCreateSettings >-------------------------------------
{*!
 * \brief Database create settings
 *
 * This class defines settings for creating a new point cloud database.
 *}
type
  TRDBPointcloudCreateSettings = class(System.TObject)
  public
    {*!
     * \brief Primary point attribute
     *
     * The primary point attribute defines the attribute that is used
     * to sort and index the points. Usually the 3D point coordinates are
     * used for that. The primary attribute is automatically added to the
     * point cloud (using Pointcloud::attributeAdd()) and cannot be deleted.
     *
     * \see riegl::rdb::pointcloud::PointAttributes
     *}
    PrimaryAttribute : TRDBPointcloudPointAttribute;

    {*!
     * \brief Point chunk mode
     *
     * Details see: TRDBPointcloudChunkMode
     *
     * Default: RDB_CHUNK_MODE_POINT_COUNT
     *}
    ChunkMode : TRDBPointcloudChunkMode;

    {*!
     * \brief Point chunk size
     *
     * Details see: TRDBPointcloudChunkMode
     *
     * Default: 65536 points
     *}
    ChunkSize : TRDBUInt32;

    {*!
     * \brief Level of detail mode
     *
     * Details see: CreateSettings::LodMode
     *
     * Default: CreateSettings::THINOUT
     *}
    LodMode : TRDBPointcloudLodMode;

    {*!
     * \brief Level of detail size
     *
     * Details see: CreateSettings::LodMode
     *
     * To disable LOD generation, set this parameter to zero (no matter which
     * LOD mode is used).
     *
     * Default: 20 (i.e. 20% of the original point count).
     *
     * \note In RDB library versions before 2.0.850 this parameter had a
     *       different meaning. To retain compatibility, the parameter was
     *       not renamed to e.g. 'overheadLOD' - hence the strange name.
       *}
    ChunkSizeLOD : TRDBUInt32;

    {*!
     * \brief Point cache size
     *
     * The database engine may buffer read and write operations in an
     * internal cache. This value defines the cache size in bytes (octets).
     *
     * Default: 500 MB
     *}
    CacheSize : TRDBUInt64;

    {*!
     * \brief Data compression level
     *
     * The database automatically compresses point data before it is
     * stored. The compression level defines the compression quality,
     * i.e. higher values produce smaller files.
     *
     * Range: 0..100 (i.e. percent)
     * Default: 10%
     *}
    CompressionLevel : TRDBUInt8;

    {*!
     * \brief Point ID optimization
     *
     * Enable this option to apply optimizations to the point ID
     * attribute (riegl.id) that can result in smaller files.
     *
     * Default: False
     *
     * \note No optimizations are applied when:
     *       - points were inserted in a previous transaction
     *       - buffers for the point ID (riegl.id) or dynamic point attributes
     *         (e.g. "riegl.selected", "riegl.visible") are passed to the insert
     *         query (QueryInsert class)
     *
     * \warning When optimizations are enabled, the point ID no longer
     *          reflects the order in which the points were inserted.
     *}
    OptimizePointID : Boolean;

    {*!
     * \brief Point insert mode
     *
     * This setting specifies how points are to be inserted into the database.
     *
     * Supported values:
     *   - "single-pass" (default)
     *          Points are sorted and inserted into the internal index structure
     *          each time QueryInsert::next() is called. This is suitable for
     *          scenarios where the same objects are only scanned once or just
     *          a few times (e.g in TLS or MLS).
     *
     *   - "multi-pass"
     *          Points are sorted and inserted into the internal index structure
     *          after the last call to QueryInsert::next() when the transaction is
     *          committed. This is suitable for scenarios where the same objects are
     *          scanned multiple times (e.g. in ALS or ULS when the system passes
     *          over the same area several times without toggling data acquisition).
     *          This mode is only supported for 3D point clouds (e.g. when the
     *          primary point attribute is "riegl.xyz") and when no points have
     *          been inserted before. Otherwise "single-pass" mode is used instead.
     *          This mode implies "optimizePointID" and point IDs are not returned
     *          by the insert query.
     *
     * \note It is recommended to only check whether the string starts with one of
     *       the above values and to ignore all subsequent characters (mode-specific
     *       parameters may be added after the mode name in the future).
     *}
    PointInsertMode : String;

  public
    destructor Destroy(); override;

    {*!
     * \brief Default constructor
     *
     * All properties are set to default values.
     *}
    constructor Create(const Context : TRDBContext); reintroduce; overload;

    {*!
     * \brief Copy constructor
     *
     * All properties are copied from the given settings object.
     *}
    constructor Create(const Settings : TRDBPointcloudCreateSettings); overload;

    {*!
     * \brief Assignment operator
     *
     * All properties are copied from the given settings object.
     *}
    function Assign(const Settings : TRDBPointcloudCreateSettings) : TRDBPointcloudCreateSettings;

    (*!
     * \brief Load settings from JSON string
     *
     * This function parses the given JSON string and applies all available
     * properties - missing properties are silently ignored (i.e. the value
     * remains unchanged). When parsing the JSON string fails, an exception
     * is thrown.
     *
     * Example JSON string:
     *
     *     {
     *         "primary_attribute": {
     *             "name": "riegl.xyz",
     *             "title": "XYZ",
     *             "description": "Cartesian point coordinates wrt. application coordinate system (0: X, 1: Y, 2: Z)",
     *             "unit_symbol": "m",
     *             "length": 3,
     *             "resolution": 0.00025,
     *             "minimum_value": -535000.0,
     *             "maximum_value": 535000.0,
     *             "default_value": 0.0,
     *             "storage_class": "variable",
     *             "compression_options": "shuffle",
     *             "scale_factor": 1.0
     *         },
     *         "chunk_mode": "point_count",
     *         "chunk_size": 65536,
     *         "lod_mode": "thinout",
     *         "chunk_size_lod": 20,
     *         "cache_size": 524288000,
     *         "compression_level": 10,
     *         "optimize_point_id": false,
     *         "point_insert_mode": "single-pass"
     *     }
     *)
    procedure Load(const JSON : String);

    {*!
     * \brief Save settings to JSON string
     * \see load()
     *}
    function Save() : String;

  private
    FContext : TRDBContext;
    FHandle  : TRDBPointcloudCreateSettingsHandle;

  public
    property Handle : TRDBPointcloudCreateSettingsHandle read FHandle;
  end;

//---< TOOLS >------------------------------------------------------------------

//______________________________________________________________________________
{*!
 * \brief Read settings from library
 * \note For wrapper internal use only.
 *}
procedure PointcloudCreateSettingsRead(const Target : TRDBPointcloudCreateSettings);

//______________________________________________________________________________
{*!
 * \brief Post settings to library
 * \note For wrapper internal use only.
 *}
procedure PointcloudCreateSettingsPost(const Source : TRDBPointcloudCreateSettings);

{******************************************************************************}
{***} IMPLEMENTATION {*********************************************************}
{******************************************************************************}

//---< INCLUDES >---------------------------------------------------------------

uses
  Math,
  SysUtils;

//---< TRDBPointcloudCreateSettings::PUBLIC >-----------------------------------

destructor TRDBPointcloudCreateSettings.Destroy();
begin
  if (FContext <> nil) and (FHandle <> nil) then
  begin
    rdb_pointcloud_create_settings_delete(FContext.Handle, FHandle);
  end;
  FreeAndNil(PrimaryAttribute);
  inherited;
end;

constructor TRDBPointcloudCreateSettings.Create(const Context : TRDBContext);
begin
  inherited Create;
  FContext := Context; FHandle := nil;
  PrimaryAttribute := TRDBPointcloudPointAttribute.Create(Context);
  FContext.Check(rdb_pointcloud_create_settings_new(FContext.Handle, FHandle));
  PointcloudCreateSettingsRead(Self);
end;

constructor TRDBPointcloudCreateSettings.Create(const Settings : TRDBPointcloudCreateSettings);
begin
  Create(Settings.FContext);
  Self.Assign(Settings);
end;

function TRDBPointcloudCreateSettings.Assign(const Settings : TRDBPointcloudCreateSettings) : TRDBPointcloudCreateSettings;
begin
  Self.Load(Settings.Save());
  Result := Self;
end;

procedure TRDBPointcloudCreateSettings.Load(const JSON : String);
begin
  FContext.Check(rdb_pointcloud_create_settings_json_load(
    FContext.Handle, FHandle, TRDBString(AnsiToUtf8(JSON))
  ));
  PointcloudCreateSettingsRead(Self);
end;

function TRDBPointcloudCreateSettings.Save() : String;
var
  JSON : TRDBString;
begin
  PointcloudCreateSettingsPost(Self);
  FContext.Check(rdb_pointcloud_create_settings_json_save(
    FContext.Handle, FHandle, JSON
  ));
  Result := AsSTDString(JSON);
end;

//---< TOOLS >------------------------------------------------------------------

procedure PointcloudCreateSettingsRead(const Target : TRDBPointcloudCreateSettings);
var
  Local : record
    LodMode         : TRDBUInt32;
    ChunkMode       : TRDBUInt32;
    OptimizePointID : TRDBUInt32;
    PointInsertMode : TRDBString;
  end;
begin
  FillChar(Local, SizeOf(Local), #0);
  //
  Target.FContext.Check(rdb_pointcloud_create_settings_get_primary_attribute(
    Target.FContext.Handle, Target.FHandle, Target.PrimaryAttribute.Handle
  ));
  PointcloudPointAttributeRead(Target.PrimaryAttribute);
  //
  Target.FContext.Check(rdb_pointcloud_create_settings_get_chunk_mode(
    Target.FContext.Handle, Target.FHandle, Local.ChunkMode
  ));                                                                           Target.ChunkMode := TRDBPointcloudChunkMode(Local.ChunkMode);
  Target.FContext.Check(rdb_pointcloud_create_settings_get_chunk_size(
    Target.FContext.Handle, Target.FHandle, Target.ChunkSize
  ));
  Target.FContext.Check(rdb_pointcloud_create_settings_get_lod_mode(
    Target.FContext.Handle, Target.FHandle, Local.LodMode
  ));                                                                           Target.LodMode := TRDBPointcloudLodMode(Local.LodMode);
  Target.FContext.Check(rdb_pointcloud_create_settings_get_chunk_size_lod(
    Target.FContext.Handle, Target.FHandle, Target.ChunkSizeLOD
  ));
  Target.FContext.Check(rdb_pointcloud_create_settings_get_cache_size_64(
    Target.FContext.Handle, Target.FHandle, Target.CacheSize
  ));
  Target.FContext.Check(rdb_pointcloud_create_settings_get_compression_level(
    Target.FContext.Handle, Target.FHandle, Target.CompressionLevel
  ));
  Target.FContext.Check(rdb_pointcloud_create_settings_get_optimize_point_id(
    Target.FContext.Handle, Target.FHandle, Local.OptimizePointID
  ));                                                                           Target.OptimizePointID := Local.OptimizePointID <> 0;
  Target.FContext.Check(rdb_pointcloud_create_settings_get_point_insert_mode(
    Target.FContext.Handle, Target.FHandle, Local.PointInsertMode
  ));                                                                           Target.PointInsertMode := AsSTDString(Local.PointInsertMode);
end;

procedure PointcloudCreateSettingsPost(const Source : TRDBPointcloudCreateSettings);
begin
  PointcloudPointAttributePost(Source.PrimaryAttribute);
  Source.FContext.Check(rdb_pointcloud_create_settings_set_primary_attribute(
    Source.FContext.Handle, Source.FHandle, Source.PrimaryAttribute.Handle
  ));
  Source.FContext.Check(rdb_pointcloud_create_settings_set_chunk_mode(
    Source.FContext.Handle, Source.FHandle, Ord(Source.ChunkMode)
  ));
  Source.FContext.Check(rdb_pointcloud_create_settings_set_chunk_size(
    Source.FContext.Handle, Source.FHandle, Source.ChunkSize
  ));
  Source.FContext.Check(rdb_pointcloud_create_settings_set_lod_mode(
    Source.FContext.Handle, Source.FHandle, Ord(Source.LodMode)
  ));
  Source.FContext.Check(rdb_pointcloud_create_settings_set_chunk_size_lod(
    Source.FContext.Handle, Source.FHandle, Source.ChunkSizeLOD
  ));
  Source.FContext.Check(rdb_pointcloud_create_settings_set_cache_size_64(
    Source.FContext.Handle, Source.FHandle, Source.CacheSize
  ));
  Source.FContext.Check(rdb_pointcloud_create_settings_set_compression_level(
    Source.FContext.Handle, Source.FHandle, Source.CompressionLevel
  ));
  Source.FContext.Check(rdb_pointcloud_create_settings_set_optimize_point_id(
    Source.FContext.Handle, Source.FHandle, IfThen(Source.OptimizePointID, 1, 0)
  ));
  Source.FContext.Check(rdb_pointcloud_create_settings_set_point_insert_mode(
    Source.FContext.Handle, Source.FHandle, TRDBString(AnsiToUtf8(Source.PointInsertMode))
  ));
end;

end.